Do not show Keyguard Presentation when occluded
..., in concurrent mode, and if it is the display being used for concurrent mode. When windows with FLAG_SHOW_WHEN_LOCKED are showing on top of keyguard, the keyguard state becomes "occluded". When this happens, we should not show the Keyguard Presentation on the display that's being used for concurrent mode. This fix allows activities with FLAG_SHOW_WHEN_LOCKED to present content to the non-default display when keyguard is locked. Fixes: 270671994 Bug: 271317597 Test: manual (b/270671994 comment#10) Test: atest KeyguardDisplayManagerTest Change-Id: I79235fdd42ee23f2f4178397937eec859c56d844
This commit is contained in:
@@ -19,27 +19,34 @@ 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;
|
||||
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.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.navigationbar.NavigationBarController;
|
||||
import com.android.systemui.navigationbar.NavigationBarView;
|
||||
import com.android.systemui.settings.DisplayTracker;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@@ -47,6 +54,7 @@ import javax.inject.Inject;
|
||||
|
||||
import dagger.Lazy;
|
||||
|
||||
@SysUISingleton
|
||||
public class KeyguardDisplayManager {
|
||||
protected static final String TAG = "KeyguardDisplayManager";
|
||||
private static final boolean DEBUG = KeyguardConstants.DEBUG;
|
||||
@@ -61,6 +69,9 @@ public class KeyguardDisplayManager {
|
||||
private boolean mShowing;
|
||||
private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
|
||||
|
||||
private final DeviceStateHelper mDeviceStateHelper;
|
||||
private final KeyguardStateController mKeyguardStateController;
|
||||
|
||||
private final SparseArray<Presentation> mPresentations = new SparseArray<>();
|
||||
|
||||
private final DisplayTracker.Callback mDisplayCallback =
|
||||
@@ -92,7 +103,9 @@ public class KeyguardDisplayManager {
|
||||
KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
|
||||
DisplayTracker displayTracker,
|
||||
@Main Executor mainExecutor,
|
||||
@UiBackground Executor uiBgExecutor) {
|
||||
@UiBackground Executor uiBgExecutor,
|
||||
DeviceStateHelper deviceStateHelper,
|
||||
KeyguardStateController keyguardStateController) {
|
||||
mContext = context;
|
||||
mNavigationBarControllerLazy = navigationBarControllerLazy;
|
||||
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
|
||||
@@ -100,6 +113,8 @@ public class KeyguardDisplayManager {
|
||||
mDisplayService = mContext.getSystemService(DisplayManager.class);
|
||||
mDisplayTracker = displayTracker;
|
||||
mDisplayTracker.addDisplayChangeCallback(mDisplayCallback, mainExecutor);
|
||||
mDeviceStateHelper = deviceStateHelper;
|
||||
mKeyguardStateController = keyguardStateController;
|
||||
}
|
||||
|
||||
private boolean isKeyguardShowable(Display display) {
|
||||
@@ -122,6 +137,18 @@ public class KeyguardDisplayManager {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (mKeyguardStateController.isOccluded()
|
||||
&& mDeviceStateHelper.isConcurrentDisplayActive(display)) {
|
||||
if (DEBUG) {
|
||||
// When activities with FLAG_SHOW_WHEN_LOCKED are shown on top of Keyguard, the
|
||||
// Keyguard state becomes "occluded". In this case, we should not show the
|
||||
// KeyguardPresentation, since the activity is presenting content onto the
|
||||
// non-default display.
|
||||
Log.i(TAG, "Do not show KeyguardPresentation when occluded and concurrent"
|
||||
+ " display is active");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -260,6 +287,53 @@ public class KeyguardDisplayManager {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper used to receive device state info from {@link DeviceStateManager}.
|
||||
*/
|
||||
static class DeviceStateHelper implements DeviceStateManager.DeviceStateCallback {
|
||||
|
||||
@Nullable
|
||||
private final DisplayAddress.Physical mRearDisplayPhysicalAddress;
|
||||
|
||||
// TODO(b/271317597): These device states should be defined in DeviceStateManager
|
||||
private final int mConcurrentState;
|
||||
private boolean mIsInConcurrentDisplayState;
|
||||
|
||||
@Inject
|
||||
DeviceStateHelper(Context context,
|
||||
DeviceStateManager deviceStateManager,
|
||||
@Main Executor mainExecutor) {
|
||||
|
||||
final String rearDisplayPhysicalAddress = context.getResources().getString(
|
||||
com.android.internal.R.string.config_rearDisplayPhysicalAddress);
|
||||
if (TextUtils.isEmpty(rearDisplayPhysicalAddress)) {
|
||||
mRearDisplayPhysicalAddress = null;
|
||||
} else {
|
||||
mRearDisplayPhysicalAddress = DisplayAddress
|
||||
.fromPhysicalDisplayId(Long.parseLong(rearDisplayPhysicalAddress));
|
||||
}
|
||||
|
||||
mConcurrentState = context.getResources().getInteger(
|
||||
com.android.internal.R.integer.config_deviceStateConcurrentRearDisplay);
|
||||
deviceStateManager.registerCallback(mainExecutor, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateChanged(int state) {
|
||||
// When concurrent state ends, the display also turns off. This is enforced in various
|
||||
// ExtensionRearDisplayPresentationTest CTS tests. So, we don't need to invoke
|
||||
// hide() since that will happen through the onDisplayRemoved callback.
|
||||
mIsInConcurrentDisplayState = state == mConcurrentState;
|
||||
}
|
||||
|
||||
boolean isConcurrentDisplayActive(Display display) {
|
||||
return mIsInConcurrentDisplayState
|
||||
&& mRearDisplayPhysicalAddress != null
|
||||
&& mRearDisplayPhysicalAddress.equals(display.getAddress());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@VisibleForTesting
|
||||
static final class KeyguardPresentation extends Presentation {
|
||||
private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
|
||||
|
||||
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.hardware.display.DisplayManagerGlobal;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
@@ -38,6 +39,7 @@ import com.android.keyguard.dagger.KeyguardStatusViewComponent;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.navigationbar.NavigationBarController;
|
||||
import com.android.systemui.settings.FakeDisplayTracker;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -58,6 +60,10 @@ public class KeyguardDisplayManagerTest extends SysuiTestCase {
|
||||
private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
|
||||
@Mock
|
||||
private KeyguardDisplayManager.KeyguardPresentation mKeyguardPresentation;
|
||||
@Mock
|
||||
private KeyguardDisplayManager.DeviceStateHelper mDeviceStateHelper;
|
||||
@Mock
|
||||
private KeyguardStateController mKeyguardStateController;
|
||||
|
||||
private Executor mMainExecutor = Runnable::run;
|
||||
private Executor mBackgroundExecutor = Runnable::run;
|
||||
@@ -76,7 +82,7 @@ public class KeyguardDisplayManagerTest extends SysuiTestCase {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mManager = spy(new KeyguardDisplayManager(mContext, () -> mNavigationBarController,
|
||||
mKeyguardStatusViewComponentFactory, mDisplayTracker, mMainExecutor,
|
||||
mBackgroundExecutor));
|
||||
mBackgroundExecutor, mDeviceStateHelper, mKeyguardStateController));
|
||||
doReturn(mKeyguardPresentation).when(mManager).createPresentation(any());
|
||||
|
||||
mDefaultDisplay = new Display(DisplayManagerGlobal.getInstance(), Display.DEFAULT_DISPLAY,
|
||||
@@ -123,4 +129,13 @@ public class KeyguardDisplayManagerTest extends SysuiTestCase {
|
||||
mManager.show();
|
||||
verify(mManager, times(1)).createPresentation(eq(mSecondaryDisplay));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShow_concurrentDisplayActive_occluded() {
|
||||
mDisplayTracker.setAllDisplays(new Display[]{mDefaultDisplay, mSecondaryDisplay});
|
||||
|
||||
when(mDeviceStateHelper.isConcurrentDisplayActive(mSecondaryDisplay)).thenReturn(true);
|
||||
when(mKeyguardStateController.isOccluded()).thenReturn(true);
|
||||
verify(mManager, never()).createPresentation(eq(mSecondaryDisplay));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user