Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8390f760 authored by Matt Pietal's avatar Matt Pietal
Browse files

Fix keyguard on secondary displays

When projecting the display and on keyguard, keyguard
should show the current clock. This code updates the
display manager to be compatible with new clocks.

Also remove the legacy presentation and delete the
associated featureflag.

Fixes: 291289304
Test: atest KeyguardDisplayManagerTest
Test: atest CtsWindowManagerDeviceDisplay:MultiDisplayKeyguardTests
Flag: ACONFIG com.android.systemui.migrate_clocks_to_blueprint
DEVELOPMENT

Change-Id: I9ccb4d04d059b7f374ac781398a113fc17fa570a
parent 83c29fa5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@
    <com.android.keyguard.KeyguardStatusView
        android:id="@+id/clock"
        android:orientation="vertical"
        android:layout_width="410dp"
        android:layout_width="@dimen/keyguard_presentation_width"
        android:layout_height="wrap_content">
        <LinearLayout
            android:layout_width="match_parent"
+2 −0
Original line number Diff line number Diff line
@@ -173,4 +173,6 @@
    <dimen name="sfps_progress_bar_thickness">6dp</dimen>
    <!-- Padding from the edge of the screen for the progress bar -->
    <dimen name="sfps_progress_bar_padding_from_edge">7dp</dimen>

    <dimen name="keyguard_presentation_width">410dp</dimen>
</resources>
+120 −11
Original line number Diff line number Diff line
@@ -19,13 +19,22 @@ package com.android.keyguard
import android.app.Presentation
import android.content.Context
import android.graphics.Color
import android.graphics.Rect
import android.os.Bundle
import android.view.Display
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.FrameLayout.LayoutParams
import com.android.keyguard.dagger.KeyguardStatusViewComponent
import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockFaceController
import com.android.systemui.res.R
import com.android.systemui.shared.clocks.ClockRegistry
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -37,6 +46,8 @@ constructor(
    @Assisted display: Display,
    context: Context,
    private val keyguardStatusViewComponentFactory: KeyguardStatusViewComponent.Factory,
    private val clockRegistry: ClockRegistry,
    private val clockEventController: ClockEventController,
) :
    Presentation(
        context,
@@ -45,31 +56,74 @@ constructor(
        WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
    ) {

    private lateinit var rootView: FrameLayout
    private var clock: View? = null
    private lateinit var keyguardStatusViewController: KeyguardStatusViewController
    private lateinit var clock: KeyguardStatusView
    private lateinit var faceController: ClockFaceController
    private lateinit var clockFrame: FrameLayout

    private val clockChangedListener =
        object : ClockRegistry.ClockChangeListener {
            override fun onCurrentClockChanged() {
                setClock(clockRegistry.createCurrentClock())
            }

            override fun onAvailableClocksChanged() {}
        }

    private val layoutChangeListener =
        object : View.OnLayoutChangeListener {
            override fun onLayoutChange(
                view: View,
                left: Int,
                top: Int,
                right: Int,
                bottom: Int,
                oldLeft: Int,
                oldTop: Int,
                oldRight: Int,
                oldBottom: Int
            ) {
                clock?.let {
                    faceController.events.onTargetRegionChanged(
                        Rect(it.left, it.top, it.width, it.height)
                    )
                }
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (migrateClocksToBlueprint()) {
            onCreateV2()
        } else {
            onCreate()
        }
    }

    fun onCreateV2() {
        rootView = FrameLayout(getContext(), null)
        rootView.setClipChildren(false)
        setContentView(rootView)

        setFullscreen()

        setClock(clockRegistry.createCurrentClock())
    }

    fun onCreate() {
        setContentView(
            LayoutInflater.from(context)
                .inflate(R.layout.keyguard_clock_presentation, /* root= */ null)
        )
        val window = window ?: error("no window available.")

        // Logic to make the lock screen fullscreen
        window.decorView.systemUiVisibility =
            (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
        window.attributes.fitInsetsTypes = 0
        window.isNavigationBarContrastEnforced = false
        window.navigationBarColor = Color.TRANSPARENT
        setFullscreen()

        clock = requireViewById(R.id.clock)
        keyguardStatusViewController =
            keyguardStatusViewComponentFactory
                .build(clock, display)
                .build(clock as KeyguardStatusView, display)
                .keyguardStatusViewController
                .apply {
                    setDisplayedOnSecondaryDisplay()
@@ -77,6 +131,61 @@ constructor(
                }
    }

    override fun onAttachedToWindow() {
        if (migrateClocksToBlueprint()) {
            clockRegistry.registerClockChangeListener(clockChangedListener)
            clockEventController.registerListeners(clock!!)

            faceController.animations.enter()
        }
    }

    override fun onDetachedFromWindow() {
        if (migrateClocksToBlueprint()) {
            clockEventController.unregisterListeners()
            clockRegistry.unregisterClockChangeListener(clockChangedListener)
        }

        super.onDetachedFromWindow()
    }

    override fun onDisplayChanged() {
        val window = window ?: error("no window available.")
        window.getDecorView().requestLayout()
    }

    private fun setClock(clockController: ClockController) {
        clock?.removeOnLayoutChangeListener(layoutChangeListener)
        rootView.removeAllViews()

        faceController = clockController.largeClock
        clock = faceController.view.also { it.addOnLayoutChangeListener(layoutChangeListener) }
        rootView.addView(
            clock,
            FrameLayout.LayoutParams(
                context.resources.getDimensionPixelSize(R.dimen.keyguard_presentation_width),
                WRAP_CONTENT,
                Gravity.CENTER,
            )
        )

        clockEventController.clock = clockController
        clockEventController.setLargeClockOnSecondaryDisplay(true)
        faceController.events.onSecondaryDisplayChanged(true)
    }

    private fun setFullscreen() {
        val window = window ?: error("no window available.")
        // Logic to make the lock screen fullscreen
        window.decorView.systemUiVisibility =
            (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
        window.attributes.fitInsetsTypes = 0
        window.isNavigationBarContrastEnforced = false
        window.navigationBarColor = Color.TRANSPARENT
    }

    /** [ConnectedDisplayKeyguardPresentation] factory. */
    @AssistedFactory
    interface Factory {
+2 −109
Original line number Diff line number Diff line
@@ -17,13 +17,10 @@ package com.android.keyguard;

import android.app.Presentation;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.DisplayManager;
import android.media.MediaRouter;
import android.media.MediaRouter.RouteInfo;
import android.os.Bundle;
import android.os.Trace;
import android.text.TextUtils;
import android.util.Log;
@@ -31,20 +28,14 @@ import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayAddress;
import android.view.DisplayInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;

import androidx.annotation.Nullable;

import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.res.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.settings.DisplayTracker;
@@ -66,10 +57,8 @@ public class KeyguardDisplayManager {
    private final DisplayManager mDisplayService;
    private final DisplayTracker mDisplayTracker;
    private final Lazy<NavigationBarController> mNavigationBarControllerLazy;
    private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
    private final ConnectedDisplayKeyguardPresentation.Factory
            mConnectedDisplayKeyguardPresentationFactory;
    private final FeatureFlags mFeatureFlags;
    private final Context mContext;

    private boolean mShowing;
@@ -106,18 +95,15 @@ public class KeyguardDisplayManager {
    @Inject
    public KeyguardDisplayManager(Context context,
            Lazy<NavigationBarController> navigationBarControllerLazy,
            KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
            DisplayTracker displayTracker,
            @Main Executor mainExecutor,
            @UiBackground Executor uiBgExecutor,
            DeviceStateHelper deviceStateHelper,
            KeyguardStateController keyguardStateController,
            ConnectedDisplayKeyguardPresentation.Factory
                    connectedDisplayKeyguardPresentationFactory,
            FeatureFlags featureFlags) {
                    connectedDisplayKeyguardPresentationFactory) {
        mContext = context;
        mNavigationBarControllerLazy = navigationBarControllerLazy;
        mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
        uiBgExecutor.execute(() -> mMediaRouter = mContext.getSystemService(MediaRouter.class));
        mDisplayService = mContext.getSystemService(DisplayManager.class);
        mDisplayTracker = displayTracker;
@@ -125,7 +111,6 @@ public class KeyguardDisplayManager {
        mDeviceStateHelper = deviceStateHelper;
        mKeyguardStateController = keyguardStateController;
        mConnectedDisplayKeyguardPresentationFactory = connectedDisplayKeyguardPresentationFactory;
        mFeatureFlags = featureFlags;
    }

    private boolean isKeyguardShowable(Display display) {
@@ -197,11 +182,7 @@ public class KeyguardDisplayManager {
    }

    Presentation createPresentation(Display display) {
        if (mFeatureFlags.isEnabled(Flags.ENABLE_CLOCK_KEYGUARD_PRESENTATION)) {
        return mConnectedDisplayKeyguardPresentationFactory.create(display);
        } else {
            return new KeyguardPresentation(mContext, display, mKeyguardStatusViewComponentFactory);
        }
    }

    /**
@@ -347,92 +328,4 @@ public class KeyguardDisplayManager {
                    && mRearDisplayPhysicalAddress.equals(display.getAddress());
        }
    }


    @VisibleForTesting
    static final class KeyguardPresentation extends Presentation {
        private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
        private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
        private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
        private KeyguardClockSwitchController mKeyguardClockSwitchController;
        private View mClock;
        private int mUsableWidth;
        private int mUsableHeight;
        private int mMarginTop;
        private int mMarginLeft;
        Runnable mMoveTextRunnable = new Runnable() {
            @Override
            public void run() {
                int x = mMarginLeft + (int) (Math.random() * (mUsableWidth - mClock.getWidth()));
                int y = mMarginTop + (int) (Math.random() * (mUsableHeight - mClock.getHeight()));
                mClock.setTranslationX(x);
                mClock.setTranslationY(y);
                mClock.postDelayed(mMoveTextRunnable, MOVE_CLOCK_TIMEOUT);
            }
        };

        KeyguardPresentation(Context context, Display display,
                KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) {
            super(context, display, R.style.Theme_SystemUI_KeyguardPresentation,
                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
            mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
            setCancelable(false);
        }

        @Override
        public void cancel() {
            // Do not allow anything to cancel KeyguardPresentation except KeyguardDisplayManager.
        }

        @Override
        public void onDetachedFromWindow() {
            mClock.removeCallbacks(mMoveTextRunnable);
        }

        @Override
        public void onDisplayChanged() {
            updateBounds();
            getWindow().getDecorView().requestLayout();
        }

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            updateBounds();

            setContentView(LayoutInflater.from(getContext())
                    .inflate(R.layout.keyguard_presentation, null));

            // Logic to make the lock screen fullscreen
            getWindow().getDecorView().setSystemUiVisibility(
                    View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            getWindow().getAttributes().setFitInsetsTypes(0 /* types */);
            getWindow().setNavigationBarContrastEnforced(false);
            getWindow().setNavigationBarColor(Color.TRANSPARENT);

            mClock = findViewById(R.id.clock);

            // Avoid screen burn in
            mClock.post(mMoveTextRunnable);

            mKeyguardClockSwitchController = mKeyguardStatusViewComponentFactory
                    .build(findViewById(R.id.clock), getDisplay())
                    .getKeyguardClockSwitchController();

            mKeyguardClockSwitchController.setOnlyClock(true);
            mKeyguardClockSwitchController.init();
        }

        private void updateBounds() {
            final Rect bounds = getWindow().getWindowManager().getMaximumWindowMetrics()
                    .getBounds();
            mUsableWidth = VIDEO_SAFE_REGION * bounds.width() / 100;
            mUsableHeight = VIDEO_SAFE_REGION * bounds.height() / 100;
            mMarginLeft = (100 - VIDEO_SAFE_REGION) * bounds.width() / 200;
            mMarginTop = (100 - VIDEO_SAFE_REGION) * bounds.height() / 200;
        }
    }
}
+5 −17
Original line number Diff line number Diff line
@@ -18,8 +18,6 @@ package com.android.keyguard;

import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;

import static com.android.systemui.flags.Flags.ENABLE_CLOCK_KEYGUARD_PRESENTATION;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
@@ -37,9 +35,7 @@ import android.view.DisplayInfo;

import androidx.test.filters.SmallTest;

import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -60,13 +56,9 @@ public class KeyguardDisplayManagerTest extends SysuiTestCase {
    @Mock
    private NavigationBarController mNavigationBarController;
    @Mock
    private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
    @Mock
    private ConnectedDisplayKeyguardPresentation.Factory
            mConnectedDisplayKeyguardPresentationFactory;
    @Mock
    private KeyguardDisplayManager.KeyguardPresentation mKeyguardPresentation;
    @Mock
    private ConnectedDisplayKeyguardPresentation mConnectedDisplayKeyguardPresentation;
    @Mock
    private KeyguardDisplayManager.DeviceStateHelper mDeviceStateHelper;
@@ -77,7 +69,6 @@ public class KeyguardDisplayManagerTest extends SysuiTestCase {
    private Executor mBackgroundExecutor = Runnable::run;
    private KeyguardDisplayManager mManager;
    private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
    private FakeFeatureFlags mFakeFeatureFlags = new FakeFeatureFlags();
    // The default and secondary displays are both in the default group
    private Display mDefaultDisplay;
    private Display mSecondaryDisplay;
@@ -88,15 +79,13 @@ public class KeyguardDisplayManagerTest extends SysuiTestCase {
    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mFakeFeatureFlags.set(ENABLE_CLOCK_KEYGUARD_PRESENTATION, false);
        mManager = spy(new KeyguardDisplayManager(mContext, () -> mNavigationBarController,
                mKeyguardStatusViewComponentFactory, mDisplayTracker, mMainExecutor,
                mBackgroundExecutor, mDeviceStateHelper, mKeyguardStateController,
                mConnectedDisplayKeyguardPresentationFactory, mFakeFeatureFlags));
        doReturn(mKeyguardPresentation).when(mManager).createPresentation(any());
                mDisplayTracker, mMainExecutor, mBackgroundExecutor, mDeviceStateHelper,
                mKeyguardStateController, mConnectedDisplayKeyguardPresentationFactory));
        doReturn(mConnectedDisplayKeyguardPresentation).when(
                mConnectedDisplayKeyguardPresentationFactory).create(any());

        doReturn(mConnectedDisplayKeyguardPresentation).when(mManager)
                .createPresentation(any());
        mDefaultDisplay = new Display(DisplayManagerGlobal.getInstance(), Display.DEFAULT_DISPLAY,
                new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS);
        mSecondaryDisplay = new Display(DisplayManagerGlobal.getInstance(),
@@ -152,9 +141,8 @@ public class KeyguardDisplayManagerTest extends SysuiTestCase {
    }

    @Test
    public void testShow_withClockPresentationFlagEnabled_presentationCreated() {
    public void testShow_presentationCreated() {
        when(mManager.createPresentation(any())).thenCallRealMethod();
        mFakeFeatureFlags.set(ENABLE_CLOCK_KEYGUARD_PRESENTATION, true);
        mDisplayTracker.setAllDisplays(new Display[]{mDefaultDisplay, mSecondaryDisplay});

        mManager.show();
Loading