Add keyguard callbacks to ShellInterface

- Currently multiple shell feature interfaces expose the same
  keyguard visibility callback, instead we can pipe this signal
  to the shell for controllers to register for events.

Bug: 238217847
Test: atest WMShellUnitTests
Test: atest SystemUITests
Change-Id: I96125e9f3796c8303683c9314f13884121ded39d
This commit is contained in:
Winson Chung
2022-07-14 18:06:03 +00:00
parent 126b3b416e
commit b50a3b4605
21 changed files with 330 additions and 216 deletions

View File

@@ -23,13 +23,4 @@ import com.android.wm.shell.common.annotations.ExternalThread;
*/
@ExternalThread
public interface CompatUI {
/**
* Called when the keyguard showing state changes. Removes all compat UIs if the
* keyguard is now showing.
*
* <p>Note that if the keyguard is occluded it will also be considered showing.
*
* @param showing indicates if the keyguard is now showing.
*/
void onKeyguardShowingChanged(boolean showing);
}

View File

@@ -42,6 +42,8 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.compatui.CompatUIWindowManager.CompatUIHintsState;
import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.transition.Transitions;
import java.lang.ref.WeakReference;
@@ -58,7 +60,7 @@ import dagger.Lazy;
* activities are in compatibility mode.
*/
public class CompatUIController implements OnDisplaysChangedListener,
DisplayImeController.ImePositionProcessor {
DisplayImeController.ImePositionProcessor, KeyguardChangeListener {
/** Callback for compat UI interaction. */
public interface CompatUICallback {
@@ -100,6 +102,7 @@ public class CompatUIController implements OnDisplaysChangedListener,
private final SparseArray<WeakReference<Context>> mDisplayContextCache = new SparseArray<>(0);
private final Context mContext;
private final ShellController mShellController;
private final DisplayController mDisplayController;
private final DisplayInsetsController mDisplayInsetsController;
private final DisplayImeController mImeController;
@@ -118,6 +121,7 @@ public class CompatUIController implements OnDisplaysChangedListener,
private boolean mKeyguardShowing;
public CompatUIController(Context context,
ShellController shellController,
DisplayController displayController,
DisplayInsetsController displayInsetsController,
DisplayImeController imeController,
@@ -125,6 +129,7 @@ public class CompatUIController implements OnDisplaysChangedListener,
ShellExecutor mainExecutor,
Lazy<Transitions> transitionsLazy) {
mContext = context;
mShellController = shellController;
mDisplayController = displayController;
mDisplayInsetsController = displayInsetsController;
mImeController = imeController;
@@ -134,6 +139,7 @@ public class CompatUIController implements OnDisplaysChangedListener,
mDisplayController.addDisplayWindowListener(this);
mImeController.addPositionProcessor(this);
mCompatUIHintsState = new CompatUIHintsState();
shellController.addKeyguardChangeListener(this);
}
/** Returns implementation of {@link CompatUI}. */
@@ -223,9 +229,10 @@ public class CompatUIController implements OnDisplaysChangedListener,
layout -> layout.updateVisibility(showOnDisplay(displayId)));
}
@VisibleForTesting
void onKeyguardShowingChanged(boolean showing) {
mKeyguardShowing = showing;
@Override
public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
boolean animatingDismiss) {
mKeyguardShowing = visible;
// Hide the compat UIs when keyguard is showing.
forAllLayouts(layout -> layout.updateVisibility(showOnDisplay(layout.getDisplayId())));
}
@@ -378,12 +385,6 @@ public class CompatUIController implements OnDisplaysChangedListener,
*/
@ExternalThread
private class CompatUIImpl implements CompatUI {
@Override
public void onKeyguardShowingChanged(boolean showing) {
mMainExecutor.execute(() -> {
CompatUIController.this.onKeyguardShowingChanged(showing);
});
}
}
/** An implementation of {@link OnInsetsChangedListener} for a given display id. */

View File

@@ -214,11 +214,12 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static CompatUIController provideCompatUIController(Context context,
ShellController shellController,
DisplayController displayController, DisplayInsetsController displayInsetsController,
DisplayImeController imeController, SyncTransactionQueue syncQueue,
@ShellMainThread ShellExecutor mainExecutor, Lazy<Transitions> transitionsLazy) {
return new CompatUIController(context, displayController, displayInsetsController,
imeController, syncQueue, mainExecutor, transitionsLazy);
return new CompatUIController(context, shellController, displayController,
displayInsetsController, imeController, syncQueue, mainExecutor, transitionsLazy);
}
@WMSingleton

View File

@@ -225,6 +225,7 @@ public abstract class WMShellModule {
@Provides
@DynamicOverride
static SplitScreenController provideSplitScreenController(
ShellController shellController,
ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
@@ -234,7 +235,7 @@ public abstract class WMShellModule {
DisplayInsetsController displayInsetsController, Transitions transitions,
TransactionPool transactionPool, IconProvider iconProvider,
Optional<RecentTasksController> recentTasks) {
return new SplitScreenController(shellTaskOrganizer, syncQueue, context,
return new SplitScreenController(shellController, shellTaskOrganizer, syncQueue, context,
rootTaskDisplayAreaOrganizer, mainExecutor, displayController, displayImeController,
displayInsetsController, transitions, transactionPool, iconProvider,
recentTasks);

View File

@@ -85,9 +85,4 @@ public interface OneHanded {
* Notifies when user switch complete
*/
void onUserSwitch(int userId);
/**
* Notifies when keyguard visibility changed
*/
void onKeyguardVisibilityChanged(boolean showing);
}

View File

@@ -55,6 +55,7 @@ import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.sysui.ConfigurationChangeListener;
import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellController;
import java.io.PrintWriter;
@@ -63,7 +64,8 @@ import java.io.PrintWriter;
* Manages and manipulates the one handed states, transitions, and gesture for phones.
*/
public class OneHandedController implements RemoteCallable<OneHandedController>,
DisplayChangeController.OnDisplayChangingListener, ConfigurationChangeListener {
DisplayChangeController.OnDisplayChangingListener, ConfigurationChangeListener,
KeyguardChangeListener {
private static final String TAG = "OneHandedController";
private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
@@ -279,6 +281,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
mState.addSListeners(mTutorialHandler);
mShellController.addConfigurationChangeListener(this);
mShellController.addKeyguardChangeListener(this);
}
public OneHanded asOneHanded() {
@@ -605,8 +608,11 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
mTutorialHandler.onConfigurationChanged();
}
private void onKeyguardVisibilityChanged(boolean showing) {
mKeyguardShowing = showing;
@Override
public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
boolean animatingDismiss) {
mKeyguardShowing = visible;
stopOneHanded();
}
private void onUserSwitch(int newUserId) {
@@ -756,13 +762,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
OneHandedController.this.onUserSwitch(userId);
});
}
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
mMainExecutor.execute(() -> {
OneHandedController.this.onKeyguardVisibilityChanged(showing);
});
}
}
/**

View File

@@ -100,23 +100,6 @@ public interface Pip {
*/
default void removePipExclusionBoundsChangeListener(Consumer<Rect> listener) { }
/**
* Called when the visibility of keyguard is changed.
* @param showing {@code true} if keyguard is now showing, {@code false} otherwise.
* @param animating {@code true} if system is animating between keyguard and surface behind,
* this only makes sense when showing is {@code false}.
*/
default void onKeyguardVisibilityChanged(boolean showing, boolean animating) { }
/**
* Called when the dismissing animation keyguard and surfaces behind is finished.
* See also {@link #onKeyguardVisibilityChanged(boolean, boolean)}.
*
* TODO(b/206741900) deprecate this path once we're able to animate the PiP window as part of
* keyguard dismiss animation.
*/
default void onKeyguardDismissAnimationFinished() { }
/**
* Dump the current state and information if need.
*

View File

@@ -88,6 +88,7 @@ import com.android.wm.shell.pip.PipTransitionState;
import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.sysui.ConfigurationChangeListener;
import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.transition.Transitions;
@@ -102,7 +103,7 @@ import java.util.function.Consumer;
* Manages the picture-in-picture (PIP) UI and states for Phones.
*/
public class PipController implements PipTransitionController.PipTransitionCallback,
RemoteCallable<PipController>, ConfigurationChangeListener {
RemoteCallable<PipController>, ConfigurationChangeListener, KeyguardChangeListener {
private static final String TAG = "PipController";
private Context mContext;
@@ -527,6 +528,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
});
mShellController.addConfigurationChangeListener(this);
mShellController.addKeyguardChangeListener(this);
}
@Override
@@ -661,21 +663,24 @@ public class PipController implements PipTransitionController.PipTransitionCallb
* finished first to reset the visibility of PiP window.
* See also {@link #onKeyguardDismissAnimationFinished()}
*/
private void onKeyguardVisibilityChanged(boolean keyguardShowing, boolean animating) {
@Override
public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
boolean animatingDismiss) {
if (!mPipTaskOrganizer.isInPip()) {
return;
}
if (keyguardShowing) {
if (visible) {
mIsKeyguardShowingOrAnimating = true;
hidePipMenu(null /* onStartCallback */, null /* onEndCallback */);
mPipTaskOrganizer.setPipVisibility(false);
} else if (!animating) {
} else if (!animatingDismiss) {
mIsKeyguardShowingOrAnimating = false;
mPipTaskOrganizer.setPipVisibility(true);
}
}
private void onKeyguardDismissAnimationFinished() {
@Override
public void onKeyguardDismissAnimationFinished() {
if (mPipTaskOrganizer.isInPip()) {
mIsKeyguardShowingOrAnimating = false;
mPipTaskOrganizer.setPipVisibility(true);
@@ -995,18 +1000,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
});
}
@Override
public void onKeyguardVisibilityChanged(boolean showing, boolean animating) {
mMainExecutor.execute(() -> {
PipController.this.onKeyguardVisibilityChanged(showing, animating);
});
}
@Override
public void onKeyguardDismissAnimationFinished() {
mMainExecutor.execute(PipController.this::onKeyguardDismissAnimationFinished);
}
@Override
public void dump(PrintWriter pw) {
try {

View File

@@ -77,12 +77,6 @@ public interface SplitScreen {
return null;
}
/**
* Called when the visibility of the keyguard changes.
* @param showing Indicates if the keyguard is now visible.
*/
void onKeyguardVisibilityChanged(boolean showing);
/** Called when device waking up finished. */
void onFinishedWakingUp();

View File

@@ -80,6 +80,8 @@ import com.android.wm.shell.draganddrop.DragAndDropPolicy;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.transition.LegacyTransitions;
import com.android.wm.shell.transition.Transitions;
@@ -99,7 +101,7 @@ import java.util.concurrent.Executor;
*/
// TODO(b/198577848): Implement split screen flicker test to consolidate CUJ of split screen.
public class SplitScreenController implements DragAndDropPolicy.Starter,
RemoteCallable<SplitScreenController> {
RemoteCallable<SplitScreenController>, KeyguardChangeListener {
private static final String TAG = SplitScreenController.class.getSimpleName();
public static final int EXIT_REASON_UNKNOWN = 0;
@@ -127,6 +129,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
@Retention(RetentionPolicy.SOURCE)
@interface ExitReason{}
private final ShellController mShellController;
private final ShellTaskOrganizer mTaskOrganizer;
private final SyncTransactionQueue mSyncQueue;
private final Context mContext;
@@ -147,7 +150,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
// outside the bounds of the roots by being reparented into a higher level fullscreen container
private SurfaceControl mSplitTasksContainerLayer;
public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer,
public SplitScreenController(ShellController shellController,
ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTDAOrganizer,
ShellExecutor mainExecutor, DisplayController displayController,
@@ -155,6 +159,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
DisplayInsetsController displayInsetsController,
Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider,
Optional<RecentTasksController> recentTasks) {
mShellController = shellController;
mTaskOrganizer = shellTaskOrganizer;
mSyncQueue = syncQueue;
mContext = context;
@@ -185,6 +190,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
public void onOrganizerRegistered() {
mShellController.addKeyguardChangeListener(this);
if (mStageCoordinator == null) {
// TODO: Multi-display
mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
@@ -283,8 +289,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mStageCoordinator.exitSplitScreen(toTopTaskId, exitReason);
}
public void onKeyguardVisibilityChanged(boolean showing) {
mStageCoordinator.onKeyguardVisibilityChanged(showing);
@Override
public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
boolean animatingDismiss) {
mStageCoordinator.onKeyguardVisibilityChanged(visible);
}
public void onFinishedWakingUp() {
@@ -657,13 +665,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
});
}
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
mMainExecutor.execute(() -> {
SplitScreenController.this.onKeyguardVisibilityChanged(showing);
});
}
@Override
public void onFinishedWakingUp() {
mMainExecutor.execute(() -> {

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.wm.shell.sysui;
/**
* Callbacks for when the keyguard changes.
*/
public interface KeyguardChangeListener {
/**
* Notifies the Shell that the keyguard is showing (and if so, whether it is occluded).
*/
default void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
boolean animatingDismiss) {}
/**
* Notifies the Shell when the keyguard dismiss animation has finished.
*
* TODO(b/206741900) deprecate this path once we're able to animate the PiP window as part of
* keyguard dismiss animation.
*/
default void onKeyguardDismissAnimationFinished() {}
}

View File

@@ -47,7 +47,9 @@ public class ShellController {
private final ShellExecutor mMainExecutor;
private final ShellInterfaceImpl mImpl = new ShellInterfaceImpl();
private final CopyOnWriteArrayList<ConfigurationChangeListener> mListeners =
private final CopyOnWriteArrayList<ConfigurationChangeListener> mConfigChangeListeners =
new CopyOnWriteArrayList<>();
private final CopyOnWriteArrayList<KeyguardChangeListener> mKeyguardChangeListeners =
new CopyOnWriteArrayList<>();
private Configuration mLastConfiguration;
@@ -68,15 +70,31 @@ public class ShellController {
* particular order.
*/
public void addConfigurationChangeListener(ConfigurationChangeListener listener) {
mListeners.remove(listener);
mListeners.add(listener);
mConfigChangeListeners.remove(listener);
mConfigChangeListeners.add(listener);
}
/**
* Removes an existing configuration listener.
*/
public void removeConfigurationChangeListener(ConfigurationChangeListener listener) {
mListeners.remove(listener);
mConfigChangeListeners.remove(listener);
}
/**
* Adds a new Keyguard listener. The Keyguard change callbacks are not made in any
* particular order.
*/
public void addKeyguardChangeListener(KeyguardChangeListener listener) {
mKeyguardChangeListeners.remove(listener);
mKeyguardChangeListeners.add(listener);
}
/**
* Removes an existing Keyguard listener.
*/
public void removeKeyguardChangeListener(KeyguardChangeListener listener) {
mKeyguardChangeListeners.remove(listener);
}
@VisibleForTesting
@@ -102,7 +120,7 @@ public class ShellController {
// Update the last configuration and call listeners
mLastConfiguration.updateFrom(newConfig);
for (ConfigurationChangeListener listener : mListeners) {
for (ConfigurationChangeListener listener : mConfigChangeListeners) {
listener.onConfigurationChanged(newConfig);
if (densityFontScaleChanged) {
listener.onDensityOrFontScaleChanged();
@@ -119,11 +137,26 @@ public class ShellController {
}
}
@VisibleForTesting
void onKeyguardVisibilityChanged(boolean visible, boolean occluded, boolean animatingDismiss) {
for (KeyguardChangeListener listener : mKeyguardChangeListeners) {
listener.onKeyguardVisibilityChanged(visible, occluded, animatingDismiss);
}
}
@VisibleForTesting
void onKeyguardDismissAnimationFinished() {
for (KeyguardChangeListener listener : mKeyguardChangeListeners) {
listener.onKeyguardDismissAnimationFinished();
}
}
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
pw.println(innerPrefix + "mListeners=" + mListeners.size());
pw.println(innerPrefix + "mConfigChangeListeners=" + mConfigChangeListeners.size());
pw.println(innerPrefix + "mLastConfiguration=" + mLastConfiguration);
pw.println(innerPrefix + "mKeyguardChangeListeners=" + mKeyguardChangeListeners.size());
}
/**
@@ -136,5 +169,19 @@ public class ShellController {
mMainExecutor.execute(() ->
ShellController.this.onConfigurationChanged(newConfiguration));
}
@Override
public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
boolean animatingDismiss) {
mMainExecutor.execute(() ->
ShellController.this.onKeyguardVisibilityChanged(visible, occluded,
animatingDismiss));
}
@Override
public void onKeyguardDismissAnimationFinished() {
mMainExecutor.execute(() ->
ShellController.this.onKeyguardDismissAnimationFinished());
}
}
}

View File

@@ -30,4 +30,16 @@ public interface ShellInterface {
* Notifies the Shell that the configuration has changed.
*/
default void onConfigurationChanged(Configuration newConfiguration) {}
/**
* Notifies the Shell that the keyguard is showing (and if so, whether it is occluded) or not
* showing, and whether it is animating a dismiss.
*/
default void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
boolean animatingDismiss) {}
/**
* Notifies the Shell when the keyguard dismiss animation has finished.
*/
default void onKeyguardDismissAnimationFinished() {}
}

View File

@@ -53,6 +53,7 @@ import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
@@ -78,6 +79,7 @@ public class CompatUIControllerTest extends ShellTestCase {
private static final int TASK_ID = 12;
private CompatUIController mController;
private @Mock ShellController mMockShellController;
private @Mock DisplayController mMockDisplayController;
private @Mock DisplayInsetsController mMockDisplayInsetsController;
private @Mock DisplayLayout mMockDisplayLayout;
@@ -105,7 +107,7 @@ public class CompatUIControllerTest extends ShellTestCase {
doReturn(TASK_ID).when(mMockLetterboxEduLayout).getTaskId();
doReturn(true).when(mMockLetterboxEduLayout).createLayout(anyBoolean());
doReturn(true).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean());
mController = new CompatUIController(mContext, mMockDisplayController,
mController = new CompatUIController(mContext, mMockShellController, mMockDisplayController,
mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor,
mMockTransitionsLazy) {
@Override
@@ -123,6 +125,11 @@ public class CompatUIControllerTest extends ShellTestCase {
spyOn(mController);
}
@Test
public void instantiateController_registerKeyguardChangeListener() {
verify(mMockShellController, times(1)).addKeyguardChangeListener(any());
}
@Test
public void testListenerRegistered() {
verify(mMockDisplayController).addDisplayWindowListener(mController);
@@ -324,7 +331,7 @@ public class CompatUIControllerTest extends ShellTestCase {
/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener);
// Verify that the restart button is hidden after keyguard becomes showing.
mController.onKeyguardShowingChanged(true);
mController.onKeyguardVisibilityChanged(true, false, false);
verify(mMockCompatLayout).updateVisibility(false);
verify(mMockLetterboxEduLayout).updateVisibility(false);
@@ -340,7 +347,7 @@ public class CompatUIControllerTest extends ShellTestCase {
false);
// Verify button is shown after keyguard becomes not showing.
mController.onKeyguardShowingChanged(false);
mController.onKeyguardVisibilityChanged(false, false, false);
verify(mMockCompatLayout).updateVisibility(true);
verify(mMockLetterboxEduLayout).updateVisibility(true);
@@ -352,7 +359,7 @@ public class CompatUIControllerTest extends ShellTestCase {
/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener);
mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ true);
mController.onKeyguardShowingChanged(true);
mController.onKeyguardVisibilityChanged(true, false, false);
verify(mMockCompatLayout, times(2)).updateVisibility(false);
verify(mMockLetterboxEduLayout, times(2)).updateVisibility(false);
@@ -360,7 +367,7 @@ public class CompatUIControllerTest extends ShellTestCase {
clearInvocations(mMockCompatLayout, mMockLetterboxEduLayout);
// Verify button remains hidden after keyguard becomes not showing since IME is showing.
mController.onKeyguardShowingChanged(false);
mController.onKeyguardVisibilityChanged(false, false, false);
verify(mMockCompatLayout).updateVisibility(false);
verify(mMockLetterboxEduLayout).updateVisibility(false);
@@ -378,7 +385,7 @@ public class CompatUIControllerTest extends ShellTestCase {
/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener);
mController.onImeVisibilityChanged(DISPLAY_ID, /* isShowing= */ true);
mController.onKeyguardShowingChanged(true);
mController.onKeyguardVisibilityChanged(true, false, false);
verify(mMockCompatLayout, times(2)).updateVisibility(false);
verify(mMockLetterboxEduLayout, times(2)).updateVisibility(false);
@@ -392,7 +399,7 @@ public class CompatUIControllerTest extends ShellTestCase {
verify(mMockLetterboxEduLayout).updateVisibility(false);
// Verify button is shown after keyguard becomes not showing.
mController.onKeyguardShowingChanged(false);
mController.onKeyguardVisibilityChanged(false, false, false);
verify(mMockCompatLayout).updateVisibility(true);
verify(mMockLetterboxEduLayout).updateVisibility(true);

View File

@@ -148,6 +148,11 @@ public class OneHandedControllerTest extends OneHandedTestCase {
verify(mMockShellController, times(1)).addConfigurationChangeListener(any());
}
@Test
public void testControllerRegistersKeyguardChangeListener() {
verify(mMockShellController, times(1)).addKeyguardChangeListener(any());
}
@Test
public void testDefaultShouldNotInOneHanded() {
// Assert default transition state is STATE_NONE

View File

@@ -122,6 +122,11 @@ public class PipControllerTest extends ShellTestCase {
verify(mMockShellController, times(1)).addConfigurationChangeListener(any());
}
@Test
public void instantiatePipController_registerKeyguardChangeListener() {
verify(mMockShellController, times(1)).addKeyguardChangeListener(any());
}
@Test
public void instantiatePipController_registersPipTransitionCallback() {
verify(mMockPipTransitionController).registerPipTransitionCallback(any());

View File

@@ -28,6 +28,9 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
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.app.ActivityManager;
import android.content.ComponentName;
@@ -44,10 +47,12 @@ import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
@@ -65,6 +70,7 @@ import java.util.Optional;
@RunWith(AndroidJUnit4.class)
public class SplitScreenControllerTests extends ShellTestCase {
@Mock ShellController mShellController;
@Mock ShellTaskOrganizer mTaskOrganizer;
@Mock SyncTransactionQueue mSyncQueue;
@Mock RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
@@ -82,10 +88,17 @@ public class SplitScreenControllerTests extends ShellTestCase {
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mSplitScreenController = spy(new SplitScreenController(mTaskOrganizer, mSyncQueue, mContext,
mRootTDAOrganizer, mMainExecutor, mDisplayController, mDisplayImeController,
mDisplayInsetsController, mTransitions, mTransactionPool, mIconProvider,
mRecentTasks));
mSplitScreenController = spy(new SplitScreenController(mShellController, mTaskOrganizer,
mSyncQueue, mContext, mRootTDAOrganizer, mMainExecutor, mDisplayController,
mDisplayImeController, mDisplayInsetsController, mTransitions, mTransactionPool,
mIconProvider, mRecentTasks));
}
@Test
public void testControllerRegistersKeyguardChangeListener() {
when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout());
mSplitScreenController.onOrganizerRegistered();
verify(mShellController, times(1)).addKeyguardChangeListener(any());
}
@Test

View File

@@ -46,12 +46,14 @@ public class ShellControllerTest extends ShellTestCase {
private ShellExecutor mExecutor;
private ShellController mController;
private TestConfigurationChangeListener mListener;
private TestConfigurationChangeListener mConfigChangeListener;
private TestKeyguardChangeListener mKeyguardChangeListener;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mListener = new TestConfigurationChangeListener();
mKeyguardChangeListener = new TestKeyguardChangeListener();
mConfigChangeListener = new TestConfigurationChangeListener();
mController = new ShellController(mExecutor);
mController.onConfigurationChanged(getConfigurationCopy());
}
@@ -61,48 +63,98 @@ public class ShellControllerTest extends ShellTestCase {
// Do nothing
}
@Test
public void testAddKeyguardChangeListener_ensureCallback() {
mController.addKeyguardChangeListener(mKeyguardChangeListener);
mController.onKeyguardVisibilityChanged(true, false, false);
assertTrue(mKeyguardChangeListener.visibilityChanged == 1);
assertTrue(mKeyguardChangeListener.dismissAnimationFinished == 0);
}
@Test
public void testDoubleAddKeyguardChangeListener_ensureSingleCallback() {
mController.addKeyguardChangeListener(mKeyguardChangeListener);
mController.addKeyguardChangeListener(mKeyguardChangeListener);
mController.onKeyguardVisibilityChanged(true, false, false);
assertTrue(mKeyguardChangeListener.visibilityChanged == 1);
assertTrue(mKeyguardChangeListener.dismissAnimationFinished == 0);
}
@Test
public void testAddRemoveKeyguardChangeListener_ensureNoCallback() {
mController.addKeyguardChangeListener(mKeyguardChangeListener);
mController.removeKeyguardChangeListener(mKeyguardChangeListener);
mController.onKeyguardVisibilityChanged(true, false, false);
assertTrue(mKeyguardChangeListener.visibilityChanged == 0);
assertTrue(mKeyguardChangeListener.dismissAnimationFinished == 0);
}
@Test
public void testKeyguardVisibilityChanged() {
mController.addKeyguardChangeListener(mKeyguardChangeListener);
mController.onKeyguardVisibilityChanged(true, true, true);
assertTrue(mKeyguardChangeListener.visibilityChanged == 1);
assertTrue(mKeyguardChangeListener.lastAnimatingDismiss);
assertTrue(mKeyguardChangeListener.lastOccluded);
assertTrue(mKeyguardChangeListener.lastAnimatingDismiss);
assertTrue(mKeyguardChangeListener.dismissAnimationFinished == 0);
}
@Test
public void testKeyguardDismissAnimationFinished() {
mController.addKeyguardChangeListener(mKeyguardChangeListener);
mController.onKeyguardDismissAnimationFinished();
assertTrue(mKeyguardChangeListener.visibilityChanged == 0);
assertTrue(mKeyguardChangeListener.dismissAnimationFinished == 1);
}
@Test
public void testAddConfigurationChangeListener_ensureCallback() {
mController.addConfigurationChangeListener(mListener);
mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.densityDpi = 200;
mController.onConfigurationChanged(newConfig);
assertTrue(mListener.configChanges == 1);
assertTrue(mConfigChangeListener.configChanges == 1);
}
@Test
public void testDoubleAddConfigurationChangeListener_ensureSingleCallback() {
mController.addConfigurationChangeListener(mListener);
mController.addConfigurationChangeListener(mListener);
mController.addConfigurationChangeListener(mConfigChangeListener);
mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.densityDpi = 200;
mController.onConfigurationChanged(newConfig);
assertTrue(mListener.configChanges == 1);
assertTrue(mConfigChangeListener.configChanges == 1);
}
@Test
public void testAddRemoveConfigurationChangeListener_ensureNoCallback() {
mController.addConfigurationChangeListener(mListener);
mController.removeConfigurationChangeListener(mListener);
mController.addConfigurationChangeListener(mConfigChangeListener);
mController.removeConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.densityDpi = 200;
mController.onConfigurationChanged(newConfig);
assertTrue(mListener.configChanges == 0);
assertTrue(mConfigChangeListener.configChanges == 0);
}
@Test
public void testMultipleConfigurationChangeListeners() {
TestConfigurationChangeListener listener2 = new TestConfigurationChangeListener();
mController.addConfigurationChangeListener(mListener);
mController.addConfigurationChangeListener(mConfigChangeListener);
mController.addConfigurationChangeListener(listener2);
Configuration newConfig = getConfigurationCopy();
newConfig.densityDpi = 200;
mController.onConfigurationChanged(newConfig);
assertTrue(mListener.configChanges == 1);
assertTrue(mConfigChangeListener.configChanges == 1);
assertTrue(listener2.configChanges == 1);
}
@@ -115,7 +167,7 @@ public class ShellControllerTest extends ShellTestCase {
}
};
mController.addConfigurationChangeListener(badListener);
mController.addConfigurationChangeListener(mListener);
mController.addConfigurationChangeListener(mConfigChangeListener);
// Ensure we don't fail just because a listener was removed mid-callback
Configuration newConfig = getConfigurationCopy();
@@ -125,77 +177,77 @@ public class ShellControllerTest extends ShellTestCase {
@Test
public void testDensityChangeCallback() {
mController.addConfigurationChangeListener(mListener);
mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.densityDpi = 200;
mController.onConfigurationChanged(newConfig);
assertTrue(mListener.configChanges == 1);
assertTrue(mListener.densityChanges == 1);
assertTrue(mListener.smallestWidthChanges == 0);
assertTrue(mListener.themeChanges == 0);
assertTrue(mListener.localeChanges == 0);
assertTrue(mConfigChangeListener.configChanges == 1);
assertTrue(mConfigChangeListener.densityChanges == 1);
assertTrue(mConfigChangeListener.smallestWidthChanges == 0);
assertTrue(mConfigChangeListener.themeChanges == 0);
assertTrue(mConfigChangeListener.localeChanges == 0);
}
@Test
public void testFontScaleChangeCallback() {
mController.addConfigurationChangeListener(mListener);
mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.fontScale = 2;
mController.onConfigurationChanged(newConfig);
assertTrue(mListener.configChanges == 1);
assertTrue(mListener.densityChanges == 1);
assertTrue(mListener.smallestWidthChanges == 0);
assertTrue(mListener.themeChanges == 0);
assertTrue(mListener.localeChanges == 0);
assertTrue(mConfigChangeListener.configChanges == 1);
assertTrue(mConfigChangeListener.densityChanges == 1);
assertTrue(mConfigChangeListener.smallestWidthChanges == 0);
assertTrue(mConfigChangeListener.themeChanges == 0);
assertTrue(mConfigChangeListener.localeChanges == 0);
}
@Test
public void testSmallestWidthChangeCallback() {
mController.addConfigurationChangeListener(mListener);
mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.smallestScreenWidthDp = 100;
mController.onConfigurationChanged(newConfig);
assertTrue(mListener.configChanges == 1);
assertTrue(mListener.densityChanges == 0);
assertTrue(mListener.smallestWidthChanges == 1);
assertTrue(mListener.themeChanges == 0);
assertTrue(mListener.localeChanges == 0);
assertTrue(mConfigChangeListener.configChanges == 1);
assertTrue(mConfigChangeListener.densityChanges == 0);
assertTrue(mConfigChangeListener.smallestWidthChanges == 1);
assertTrue(mConfigChangeListener.themeChanges == 0);
assertTrue(mConfigChangeListener.localeChanges == 0);
}
@Test
public void testThemeChangeCallback() {
mController.addConfigurationChangeListener(mListener);
mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.assetsSeq++;
mController.onConfigurationChanged(newConfig);
assertTrue(mListener.configChanges == 1);
assertTrue(mListener.densityChanges == 0);
assertTrue(mListener.smallestWidthChanges == 0);
assertTrue(mListener.themeChanges == 1);
assertTrue(mListener.localeChanges == 0);
assertTrue(mConfigChangeListener.configChanges == 1);
assertTrue(mConfigChangeListener.densityChanges == 0);
assertTrue(mConfigChangeListener.smallestWidthChanges == 0);
assertTrue(mConfigChangeListener.themeChanges == 1);
assertTrue(mConfigChangeListener.localeChanges == 0);
}
@Test
public void testNightModeChangeCallback() {
mController.addConfigurationChangeListener(mListener);
mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
newConfig.uiMode = Configuration.UI_MODE_NIGHT_YES;
mController.onConfigurationChanged(newConfig);
assertTrue(mListener.configChanges == 1);
assertTrue(mListener.densityChanges == 0);
assertTrue(mListener.smallestWidthChanges == 0);
assertTrue(mListener.themeChanges == 1);
assertTrue(mListener.localeChanges == 0);
assertTrue(mConfigChangeListener.configChanges == 1);
assertTrue(mConfigChangeListener.densityChanges == 0);
assertTrue(mConfigChangeListener.smallestWidthChanges == 0);
assertTrue(mConfigChangeListener.themeChanges == 1);
assertTrue(mConfigChangeListener.localeChanges == 0);
}
@Test
public void testLocaleChangeCallback() {
mController.addConfigurationChangeListener(mListener);
mController.addConfigurationChangeListener(mConfigChangeListener);
Configuration newConfig = getConfigurationCopy();
// Just change the locales to be different
@@ -205,11 +257,11 @@ public class ShellControllerTest extends ShellTestCase {
newConfig.locale = Locale.CANADA;
}
mController.onConfigurationChanged(newConfig);
assertTrue(mListener.configChanges == 1);
assertTrue(mListener.densityChanges == 0);
assertTrue(mListener.smallestWidthChanges == 0);
assertTrue(mListener.themeChanges == 0);
assertTrue(mListener.localeChanges == 1);
assertTrue(mConfigChangeListener.configChanges == 1);
assertTrue(mConfigChangeListener.densityChanges == 0);
assertTrue(mConfigChangeListener.smallestWidthChanges == 0);
assertTrue(mConfigChangeListener.themeChanges == 0);
assertTrue(mConfigChangeListener.localeChanges == 1);
}
private Configuration getConfigurationCopy() {
@@ -253,4 +305,27 @@ public class ShellControllerTest extends ShellTestCase {
localeChanges++;
}
}
private class TestKeyguardChangeListener implements KeyguardChangeListener {
// Counts of number of times each of the callbacks are called
public int visibilityChanged;
public boolean lastVisibility;
public boolean lastOccluded;
public boolean lastAnimatingDismiss;
public int dismissAnimationFinished;
@Override
public void onKeyguardVisibilityChanged(boolean visible, boolean occluded,
boolean animatingDismiss) {
lastVisibility = visible;
lastOccluded = occluded;
lastAnimatingDismiss = animatingDismiss;
visibilityChanged++;
}
@Override
public void onKeyguardDismissAnimationFinished() {
dismissAnimationFinished++;
}
}
}

View File

@@ -34,7 +34,6 @@ import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;

View File

@@ -127,10 +127,7 @@ public final class WMShell extends CoreStartable
private final Executor mSysUiMainExecutor;
private boolean mIsSysUiStateValid;
private KeyguardUpdateMonitorCallback mSplitScreenKeyguardCallback;
private KeyguardUpdateMonitorCallback mPipKeyguardCallback;
private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback;
private KeyguardStateController.Callback mCompatUIKeyguardCallback;
private WakefulnessLifecycle.Observer mWakefulnessObserver;
@Inject
@@ -185,6 +182,22 @@ public final class WMShell extends CoreStartable
}
});
// Subscribe to keyguard changes
mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
@Override
public void onKeyguardShowingChanged() {
mShell.onKeyguardVisibilityChanged(mKeyguardStateController.isShowing(),
mKeyguardStateController.isOccluded(),
mKeyguardStateController.isAnimatingBetweenKeyguardAndSurfaceBehind());
}
});
mKeyguardUpdateMonitor.registerCallback(new KeyguardUpdateMonitorCallback() {
@Override
public void onKeyguardDismissAnimationFinished() {
mShell.onKeyguardDismissAnimationFinished();
}
});
// TODO: Consider piping config change and other common calls to a shell component to
// delegate internally
mProtoTracer.add(this);
@@ -192,7 +205,6 @@ public final class WMShell extends CoreStartable
mPipOptional.ifPresent(this::initPip);
mSplitScreenOptional.ifPresent(this::initSplitScreen);
mOneHandedOptional.ifPresent(this::initOneHanded);
mCompatUIOptional.ifPresent(this::initCompatUi);
}
@VisibleForTesting
@@ -204,20 +216,6 @@ public final class WMShell extends CoreStartable
}
});
mPipKeyguardCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
pip.onKeyguardVisibilityChanged(showing,
mKeyguardStateController.isAnimatingBetweenKeyguardAndSurfaceBehind());
}
@Override
public void onKeyguardDismissAnimationFinished() {
pip.onKeyguardDismissAnimationFinished();
}
};
mKeyguardUpdateMonitor.registerCallback(mPipKeyguardCallback);
mSysUiState.addCallback(sysUiStateFlag -> {
mIsSysUiStateValid = (sysUiStateFlag & INVALID_SYSUI_STATE_MASK) == 0;
pip.onSystemUiStateChanged(mIsSysUiStateValid, sysUiStateFlag);
@@ -230,14 +228,6 @@ public final class WMShell extends CoreStartable
@VisibleForTesting
void initSplitScreen(SplitScreen splitScreen) {
mSplitScreenKeyguardCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
splitScreen.onKeyguardVisibilityChanged(showing);
}
};
mKeyguardUpdateMonitor.registerCallback(mSplitScreenKeyguardCallback);
mWakefulnessLifecycle.addObserver(new WakefulnessLifecycle.Observer() {
@Override
public void onFinishedWakingUp() {
@@ -283,13 +273,8 @@ public final class WMShell extends CoreStartable
}
});
// TODO: Either move into ShellInterface or register a receiver on the Shell side directly
mOneHandedKeyguardCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
oneHanded.onKeyguardVisibilityChanged(showing);
oneHanded.stopOneHanded();
}
@Override
public void onUserSwitchComplete(int userId) {
oneHanded.onUserSwitch(userId);
@@ -340,17 +325,6 @@ public final class WMShell extends CoreStartable
});
}
@VisibleForTesting
void initCompatUi(CompatUI sizeCompatUI) {
mCompatUIKeyguardCallback = new KeyguardStateController.Callback() {
@Override
public void onKeyguardShowingChanged() {
sizeCompatUI.onKeyguardShowingChanged(mKeyguardStateController.isShowing());
}
};
mKeyguardStateController.addCallback(mCompatUIKeyguardCallback);
}
@Override
public void writeToProto(SystemUiTraceProto proto) {
if (proto.wmShell == null) {

View File

@@ -24,12 +24,10 @@ import android.test.suitebuilder.annotation.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -71,7 +69,6 @@ public class WMShellTest extends SysuiTestCase {
@Mock ConfigurationController mConfigurationController;
@Mock KeyguardStateController mKeyguardStateController;
@Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock NavigationModeController mNavigationModeController;
@Mock ScreenLifecycle mScreenLifecycle;
@Mock SysUiState mSysUiState;
@Mock Pip mPip;
@@ -106,28 +103,13 @@ public class WMShellTest extends SysuiTestCase {
verify(mCommandQueue).addCallback(any(CommandQueue.Callbacks.class));
}
@Test
public void initSplitScreen_registersCallbacks() {
mWMShell.initSplitScreen(mSplitScreen);
verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
}
@Test
public void initOneHanded_registersCallbacks() {
mWMShell.initOneHanded(mOneHanded);
verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
verify(mCommandQueue).addCallback(any(CommandQueue.Callbacks.class));
verify(mScreenLifecycle).addObserver(any(ScreenLifecycle.Observer.class));
verify(mOneHanded).registerTransitionCallback(any(OneHandedTransitionCallback.class));
verify(mOneHanded).registerEventCallback(any(OneHandedEventCallback.class));
}
@Test
public void initCompatUI_registersCallbacks() {
mWMShell.initCompatUi(mCompatUI);
verify(mKeyguardStateController).addCallback(any(KeyguardStateController.Callback.class));
}
}