Pipe user changed events to the Shell
- Move PipController and OneHandedController to use this call internally instead of exposing it to SysUI Bug: 238217847 Test: atest WMShellUnitTests Test: atest PinnedStackTests Test: Test switching users with PIP & One handed mode Test: enable WM_SHELL_SYSUI_EVENTS protologs and verify Change-Id: I0f016aabb945eb8ce80ee4d4203122659d668b8f
This commit is contained in:
@@ -66,6 +66,7 @@ public abstract class TvPipModule {
|
||||
@Provides
|
||||
static Optional<Pip> providePip(
|
||||
Context context,
|
||||
ShellInit shellInit,
|
||||
ShellController shellController,
|
||||
TvPipBoundsState tvPipBoundsState,
|
||||
TvPipBoundsAlgorithm tvPipBoundsAlgorithm,
|
||||
@@ -84,6 +85,7 @@ public abstract class TvPipModule {
|
||||
return Optional.of(
|
||||
TvPipController.create(
|
||||
context,
|
||||
shellInit,
|
||||
shellController,
|
||||
tvPipBoundsState,
|
||||
tvPipBoundsAlgorithm,
|
||||
|
||||
@@ -80,9 +80,4 @@ public interface OneHanded {
|
||||
* transition start or finish
|
||||
*/
|
||||
void registerTransitionCallback(OneHandedTransitionCallback callback);
|
||||
|
||||
/**
|
||||
* Notifies when user switch complete
|
||||
*/
|
||||
void onUserSwitch(int userId);
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ import com.android.wm.shell.sysui.KeyguardChangeListener;
|
||||
import com.android.wm.shell.sysui.ShellCommandHandler;
|
||||
import com.android.wm.shell.sysui.ShellController;
|
||||
import com.android.wm.shell.sysui.ShellInit;
|
||||
import com.android.wm.shell.sysui.UserChangeListener;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
@@ -67,7 +68,7 @@ import java.io.PrintWriter;
|
||||
*/
|
||||
public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
DisplayChangeController.OnDisplayChangingListener, ConfigurationChangeListener,
|
||||
KeyguardChangeListener {
|
||||
KeyguardChangeListener, UserChangeListener {
|
||||
private static final String TAG = "OneHandedController";
|
||||
|
||||
private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
|
||||
@@ -294,6 +295,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
mState.addSListeners(mTutorialHandler);
|
||||
mShellController.addConfigurationChangeListener(this);
|
||||
mShellController.addKeyguardChangeListener(this);
|
||||
mShellController.addUserChangeListener(this);
|
||||
}
|
||||
|
||||
public OneHanded asOneHanded() {
|
||||
@@ -627,7 +629,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
stopOneHanded();
|
||||
}
|
||||
|
||||
private void onUserSwitch(int newUserId) {
|
||||
@Override
|
||||
public void onUserChanged(int newUserId, @NonNull Context userContext) {
|
||||
unregisterSettingObservers();
|
||||
mUserId = newUserId;
|
||||
registerSettingObservers(newUserId);
|
||||
@@ -770,13 +773,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
|
||||
OneHandedController.this.registerTransitionCallback(callback);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserSwitch(int userId) {
|
||||
mMainExecutor.execute(() -> {
|
||||
OneHandedController.this.onUserSwitch(userId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,12 +50,6 @@ public interface Pip {
|
||||
default void onSystemUiStateChanged(boolean isSysUiStateValid, int flag) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the session listener for the current user.
|
||||
*/
|
||||
default void registerSessionListenerForCurrentUser() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets both shelf visibility and its height.
|
||||
*
|
||||
|
||||
@@ -92,6 +92,7 @@ import com.android.wm.shell.sysui.KeyguardChangeListener;
|
||||
import com.android.wm.shell.sysui.ShellCommandHandler;
|
||||
import com.android.wm.shell.sysui.ShellController;
|
||||
import com.android.wm.shell.sysui.ShellInit;
|
||||
import com.android.wm.shell.sysui.UserChangeListener;
|
||||
import com.android.wm.shell.transition.Transitions;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -105,7 +106,8 @@ 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, KeyguardChangeListener {
|
||||
RemoteCallable<PipController>, ConfigurationChangeListener, KeyguardChangeListener,
|
||||
UserChangeListener {
|
||||
private static final String TAG = "PipController";
|
||||
|
||||
private Context mContext;
|
||||
@@ -528,7 +530,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
});
|
||||
|
||||
mOneHandedController.ifPresent(controller -> {
|
||||
controller.asOneHanded().registerTransitionCallback(
|
||||
controller.registerTransitionCallback(
|
||||
new OneHandedTransitionCallback() {
|
||||
@Override
|
||||
public void onStartFinished(Rect bounds) {
|
||||
@@ -542,8 +544,11 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
});
|
||||
});
|
||||
|
||||
mMediaController.registerSessionListenerForCurrentUser();
|
||||
|
||||
mShellController.addConfigurationChangeListener(this);
|
||||
mShellController.addKeyguardChangeListener(this);
|
||||
mShellController.addUserChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -556,6 +561,12 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
return mMainExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserChanged(int newUserId, @NonNull Context userContext) {
|
||||
// Re-register the media session listener when switching users
|
||||
mMediaController.registerSessionListenerForCurrentUser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
mPipBoundsAlgorithm.onConfigurationChanged(mContext);
|
||||
@@ -644,10 +655,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
}
|
||||
}
|
||||
|
||||
private void registerSessionListenerForCurrentUser() {
|
||||
mMediaController.registerSessionListenerForCurrentUser();
|
||||
}
|
||||
|
||||
private void onSystemUiStateChanged(boolean isValidState, int flag) {
|
||||
mTouchHandler.onSystemUiStateChanged(isValidState);
|
||||
}
|
||||
@@ -967,13 +974,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSessionListenerForCurrentUser() {
|
||||
mMainExecutor.execute(() -> {
|
||||
PipController.this.registerSessionListenerForCurrentUser();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShelfHeight(boolean visible, int height) {
|
||||
mMainExecutor.execute(() -> {
|
||||
|
||||
@@ -32,6 +32,8 @@ import android.graphics.Rect;
|
||||
import android.os.RemoteException;
|
||||
import android.view.Gravity;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.protolog.common.ProtoLog;
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.WindowManagerShellWrapper;
|
||||
@@ -51,6 +53,8 @@ import com.android.wm.shell.pip.PipTransitionController;
|
||||
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||
import com.android.wm.shell.sysui.ConfigurationChangeListener;
|
||||
import com.android.wm.shell.sysui.ShellController;
|
||||
import com.android.wm.shell.sysui.ShellInit;
|
||||
import com.android.wm.shell.sysui.UserChangeListener;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -64,7 +68,7 @@ import java.util.Set;
|
||||
public class TvPipController implements PipTransitionController.PipTransitionCallback,
|
||||
TvPipBoundsController.PipBoundsListener, TvPipMenuController.Delegate,
|
||||
TvPipNotificationController.Delegate, DisplayController.OnDisplaysChangedListener,
|
||||
ConfigurationChangeListener {
|
||||
ConfigurationChangeListener, UserChangeListener {
|
||||
private static final String TAG = "TvPipController";
|
||||
static final boolean DEBUG = false;
|
||||
|
||||
@@ -105,6 +109,11 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
|
||||
private final PipMediaController mPipMediaController;
|
||||
private final TvPipNotificationController mPipNotificationController;
|
||||
private final TvPipMenuController mTvPipMenuController;
|
||||
private final PipTransitionController mPipTransitionController;
|
||||
private final TaskStackListenerImpl mTaskStackListener;
|
||||
private final PipParamsChangedForwarder mPipParamsChangedForwarder;
|
||||
private final DisplayController mDisplayController;
|
||||
private final WindowManagerShellWrapper mWmShellWrapper;
|
||||
private final ShellExecutor mMainExecutor;
|
||||
private final TvPipImpl mImpl = new TvPipImpl();
|
||||
|
||||
@@ -121,6 +130,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
|
||||
|
||||
public static Pip create(
|
||||
Context context,
|
||||
ShellInit shellInit,
|
||||
ShellController shellController,
|
||||
TvPipBoundsState tvPipBoundsState,
|
||||
TvPipBoundsAlgorithm tvPipBoundsAlgorithm,
|
||||
@@ -138,6 +148,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
|
||||
ShellExecutor mainExecutor) {
|
||||
return new TvPipController(
|
||||
context,
|
||||
shellInit,
|
||||
shellController,
|
||||
tvPipBoundsState,
|
||||
tvPipBoundsAlgorithm,
|
||||
@@ -157,6 +168,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
|
||||
|
||||
private TvPipController(
|
||||
Context context,
|
||||
ShellInit shellInit,
|
||||
ShellController shellController,
|
||||
TvPipBoundsState tvPipBoundsState,
|
||||
TvPipBoundsAlgorithm tvPipBoundsAlgorithm,
|
||||
@@ -170,11 +182,12 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
|
||||
TaskStackListenerImpl taskStackListener,
|
||||
PipParamsChangedForwarder pipParamsChangedForwarder,
|
||||
DisplayController displayController,
|
||||
WindowManagerShellWrapper wmShell,
|
||||
WindowManagerShellWrapper wmShellWrapper,
|
||||
ShellExecutor mainExecutor) {
|
||||
mContext = context;
|
||||
mMainExecutor = mainExecutor;
|
||||
mShellController = shellController;
|
||||
mDisplayController = displayController;
|
||||
|
||||
mTvPipBoundsState = tvPipBoundsState;
|
||||
mTvPipBoundsState.setDisplayId(context.getDisplayId());
|
||||
@@ -193,16 +206,32 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
|
||||
|
||||
mAppOpsListener = pipAppOpsListener;
|
||||
mPipTaskOrganizer = pipTaskOrganizer;
|
||||
pipTransitionController.registerPipTransitionCallback(this);
|
||||
mPipTransitionController = pipTransitionController;
|
||||
mPipParamsChangedForwarder = pipParamsChangedForwarder;
|
||||
mTaskStackListener = taskStackListener;
|
||||
mWmShellWrapper = wmShellWrapper;
|
||||
shellInit.addInitCallback(this::onInit, this);
|
||||
}
|
||||
|
||||
private void onInit() {
|
||||
mPipTransitionController.registerPipTransitionCallback(this);
|
||||
|
||||
loadConfigurations();
|
||||
|
||||
registerPipParamsChangedListener(pipParamsChangedForwarder);
|
||||
registerTaskStackListenerCallback(taskStackListener);
|
||||
registerWmShellPinnedStackListener(wmShell);
|
||||
displayController.addDisplayWindowListener(this);
|
||||
registerPipParamsChangedListener(mPipParamsChangedForwarder);
|
||||
registerTaskStackListenerCallback(mTaskStackListener);
|
||||
registerWmShellPinnedStackListener(mWmShellWrapper);
|
||||
registerSessionListenerForCurrentUser();
|
||||
mDisplayController.addDisplayWindowListener(this);
|
||||
|
||||
mShellController.addConfigurationChangeListener(this);
|
||||
mShellController.addUserChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserChanged(int newUserId, @NonNull Context userContext) {
|
||||
// Re-register the media session listener when switching users
|
||||
registerSessionListenerForCurrentUser();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -679,11 +708,6 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
|
||||
}
|
||||
|
||||
private class TvPipImpl implements Pip {
|
||||
@Override
|
||||
public void registerSessionListenerForCurrentUser() {
|
||||
mMainExecutor.execute(() -> {
|
||||
TvPipController.this.registerSessionListenerForCurrentUser();
|
||||
});
|
||||
}
|
||||
// Not used
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@ package com.android.wm.shell.sysui;
|
||||
*/
|
||||
public interface KeyguardChangeListener {
|
||||
/**
|
||||
* Notifies the Shell that the keyguard is showing (and if so, whether it is occluded).
|
||||
* Called when 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.
|
||||
* Called 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.
|
||||
|
||||
@@ -25,7 +25,9 @@ import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
|
||||
|
||||
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SYSUI_EVENTS;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Configuration;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -36,6 +38,7 @@ import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.annotations.ExternalThread;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
@@ -53,6 +56,9 @@ public class ShellController {
|
||||
new CopyOnWriteArrayList<>();
|
||||
private final CopyOnWriteArrayList<KeyguardChangeListener> mKeyguardChangeListeners =
|
||||
new CopyOnWriteArrayList<>();
|
||||
private final CopyOnWriteArrayList<UserChangeListener> mUserChangeListeners =
|
||||
new CopyOnWriteArrayList<>();
|
||||
|
||||
private Configuration mLastConfiguration;
|
||||
|
||||
|
||||
@@ -102,6 +108,22 @@ public class ShellController {
|
||||
mKeyguardChangeListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new user-change listener. The user change callbacks are not made in any
|
||||
* particular order.
|
||||
*/
|
||||
public void addUserChangeListener(UserChangeListener listener) {
|
||||
mUserChangeListeners.remove(listener);
|
||||
mUserChangeListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an existing user-change listener.
|
||||
*/
|
||||
public void removeUserChangeListener(UserChangeListener listener) {
|
||||
mUserChangeListeners.remove(listener);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void onConfigurationChanged(Configuration newConfig) {
|
||||
// The initial config is send on startup and doesn't trigger listener callbacks
|
||||
@@ -144,6 +166,8 @@ public class ShellController {
|
||||
|
||||
@VisibleForTesting
|
||||
void onKeyguardVisibilityChanged(boolean visible, boolean occluded, boolean animatingDismiss) {
|
||||
ProtoLog.v(WM_SHELL_SYSUI_EVENTS, "Keyguard visibility changed: visible=%b "
|
||||
+ "occluded=%b animatingDismiss=%b", visible, occluded, animatingDismiss);
|
||||
for (KeyguardChangeListener listener : mKeyguardChangeListeners) {
|
||||
listener.onKeyguardVisibilityChanged(visible, occluded, animatingDismiss);
|
||||
}
|
||||
@@ -151,17 +175,35 @@ public class ShellController {
|
||||
|
||||
@VisibleForTesting
|
||||
void onKeyguardDismissAnimationFinished() {
|
||||
ProtoLog.v(WM_SHELL_SYSUI_EVENTS, "Keyguard dismiss animation finished");
|
||||
for (KeyguardChangeListener listener : mKeyguardChangeListeners) {
|
||||
listener.onKeyguardDismissAnimationFinished();
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void onUserChanged(int newUserId, @NonNull Context userContext) {
|
||||
ProtoLog.v(WM_SHELL_SYSUI_EVENTS, "User changed: id=%d", newUserId);
|
||||
for (UserChangeListener listener : mUserChangeListeners) {
|
||||
listener.onUserChanged(newUserId, userContext);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void onUserProfilesChanged(@NonNull List<UserInfo> profiles) {
|
||||
ProtoLog.v(WM_SHELL_SYSUI_EVENTS, "User profiles changed");
|
||||
for (UserChangeListener listener : mUserChangeListeners) {
|
||||
listener.onUserProfilesChanged(profiles);
|
||||
}
|
||||
}
|
||||
|
||||
public void dump(@NonNull PrintWriter pw, String prefix) {
|
||||
final String innerPrefix = prefix + " ";
|
||||
pw.println(prefix + TAG);
|
||||
pw.println(innerPrefix + "mConfigChangeListeners=" + mConfigChangeListeners.size());
|
||||
pw.println(innerPrefix + "mLastConfiguration=" + mLastConfiguration);
|
||||
pw.println(innerPrefix + "mKeyguardChangeListeners=" + mKeyguardChangeListeners.size());
|
||||
pw.println(innerPrefix + "mUserChangeListeners=" + mUserChangeListeners.size());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,5 +262,17 @@ public class ShellController {
|
||||
mMainExecutor.execute(() ->
|
||||
ShellController.this.onKeyguardDismissAnimationFinished());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserChanged(int newUserId, @NonNull Context userContext) {
|
||||
mMainExecutor.execute(() ->
|
||||
ShellController.this.onUserChanged(newUserId, userContext));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserProfilesChanged(@NonNull List<UserInfo> profiles) {
|
||||
mMainExecutor.execute(() ->
|
||||
ShellController.this.onUserProfilesChanged(profiles));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,14 @@
|
||||
|
||||
package com.android.wm.shell.sysui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Configuration;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* General interface for notifying the Shell of common SysUI events like configuration or keyguard
|
||||
@@ -59,4 +64,14 @@ public interface ShellInterface {
|
||||
* Notifies the Shell when the keyguard dismiss animation has finished.
|
||||
*/
|
||||
default void onKeyguardDismissAnimationFinished() {}
|
||||
|
||||
/**
|
||||
* Notifies the Shell when the user changes.
|
||||
*/
|
||||
default void onUserChanged(int newUserId, @NonNull Context userContext) {}
|
||||
|
||||
/**
|
||||
* Notifies the Shell when a profile belonging to the user changes.
|
||||
*/
|
||||
default void onUserProfilesChanged(@NonNull List<UserInfo> profiles) {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Callbacks for when the user or user's profiles changes.
|
||||
*/
|
||||
public interface UserChangeListener {
|
||||
/**
|
||||
* Called when the current (parent) user changes.
|
||||
*/
|
||||
default void onUserChanged(int newUserId, @NonNull Context userContext) {}
|
||||
|
||||
/**
|
||||
* Called when a profile belonging to the user changes.
|
||||
*/
|
||||
default void onUserProfilesChanged(@NonNull List<UserInfo> profiles) {}
|
||||
}
|
||||
@@ -170,6 +170,11 @@ public class OneHandedControllerTest extends OneHandedTestCase {
|
||||
verify(mMockShellController, times(1)).addKeyguardChangeListener(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testControllerRegistersUserChangeListener() {
|
||||
verify(mMockShellController, times(1)).addUserChangeListener(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultShouldNotInOneHanded() {
|
||||
// Assert default transition state is STATE_NONE
|
||||
|
||||
@@ -23,6 +23,7 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -77,9 +78,9 @@ import java.util.Set;
|
||||
public class PipControllerTest extends ShellTestCase {
|
||||
private PipController mPipController;
|
||||
private ShellInit mShellInit;
|
||||
private ShellController mShellController;
|
||||
|
||||
@Mock private ShellCommandHandler mMockShellCommandHandler;
|
||||
@Mock private ShellController mMockShellController;
|
||||
@Mock private DisplayController mMockDisplayController;
|
||||
@Mock private PhonePipMenuController mMockPhonePipMenuController;
|
||||
@Mock private PipAppOpsListener mMockPipAppOpsListener;
|
||||
@@ -110,8 +111,10 @@ public class PipControllerTest extends ShellTestCase {
|
||||
return null;
|
||||
}).when(mMockExecutor).execute(any());
|
||||
mShellInit = spy(new ShellInit(mMockExecutor));
|
||||
mShellController = spy(new ShellController(mShellInit, mMockShellCommandHandler,
|
||||
mMockExecutor));
|
||||
mPipController = new PipController(mContext, mShellInit, mMockShellCommandHandler,
|
||||
mMockShellController, mMockDisplayController, mMockPipAppOpsListener,
|
||||
mShellController, mMockDisplayController, mMockPipAppOpsListener,
|
||||
mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
|
||||
mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
|
||||
mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
|
||||
@@ -135,12 +138,22 @@ public class PipControllerTest extends ShellTestCase {
|
||||
|
||||
@Test
|
||||
public void instantiatePipController_registerConfigChangeListener() {
|
||||
verify(mMockShellController, times(1)).addConfigurationChangeListener(any());
|
||||
verify(mShellController, times(1)).addConfigurationChangeListener(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void instantiatePipController_registerKeyguardChangeListener() {
|
||||
verify(mMockShellController, times(1)).addKeyguardChangeListener(any());
|
||||
verify(mShellController, times(1)).addKeyguardChangeListener(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void instantiatePipController_registerUserChangeListener() {
|
||||
verify(mShellController, times(1)).addUserChangeListener(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void instantiatePipController_registerMediaListener() {
|
||||
verify(mMockPipMediaController, times(1)).registerSessionListenerForCurrentUser();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -167,7 +180,7 @@ public class PipControllerTest extends ShellTestCase {
|
||||
|
||||
ShellInit shellInit = new ShellInit(mMockExecutor);
|
||||
assertNull(PipController.create(spyContext, shellInit, mMockShellCommandHandler,
|
||||
mMockShellController, mMockDisplayController, mMockPipAppOpsListener,
|
||||
mShellController, mMockDisplayController, mMockPipAppOpsListener,
|
||||
mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
|
||||
mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
|
||||
mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
|
||||
@@ -264,4 +277,11 @@ public class PipControllerTest extends ShellTestCase {
|
||||
|
||||
verify(mMockPipBoundsState).setKeepClearAreas(Set.of(keepClearArea), Set.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUserChangeRegisterMediaListener() {
|
||||
reset(mMockPipMediaController);
|
||||
mShellController.asShell().onUserChanged(100, mContext);
|
||||
verify(mMockPipMediaController, times(1)).registerSessionListenerForCurrentUser();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,15 @@
|
||||
package com.android.wm.shell.sysui;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
@@ -35,6 +39,8 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@SmallTest
|
||||
@@ -42,22 +48,29 @@ import java.util.Locale;
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
public class ShellControllerTest extends ShellTestCase {
|
||||
|
||||
private static final int TEST_USER_ID = 100;
|
||||
|
||||
@Mock
|
||||
private ShellInit mShellInit;
|
||||
@Mock
|
||||
private ShellCommandHandler mShellCommandHandler;
|
||||
@Mock
|
||||
private ShellExecutor mExecutor;
|
||||
@Mock
|
||||
private Context mTestUserContext;
|
||||
|
||||
private ShellController mController;
|
||||
private TestConfigurationChangeListener mConfigChangeListener;
|
||||
private TestKeyguardChangeListener mKeyguardChangeListener;
|
||||
private TestUserChangeListener mUserChangeListener;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mKeyguardChangeListener = new TestKeyguardChangeListener();
|
||||
mConfigChangeListener = new TestConfigurationChangeListener();
|
||||
mUserChangeListener = new TestUserChangeListener();
|
||||
mController = new ShellController(mShellInit, mShellCommandHandler, mExecutor);
|
||||
mController.onConfigurationChanged(getConfigurationCopy());
|
||||
}
|
||||
@@ -67,6 +80,46 @@ public class ShellControllerTest extends ShellTestCase {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddUserChangeListener_ensureCallback() {
|
||||
mController.addUserChangeListener(mUserChangeListener);
|
||||
|
||||
mController.onUserChanged(TEST_USER_ID, mTestUserContext);
|
||||
assertTrue(mUserChangeListener.userChanged == 1);
|
||||
assertTrue(mUserChangeListener.lastUserContext == mTestUserContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleAddUserChangeListener_ensureSingleCallback() {
|
||||
mController.addUserChangeListener(mUserChangeListener);
|
||||
mController.addUserChangeListener(mUserChangeListener);
|
||||
|
||||
mController.onUserChanged(TEST_USER_ID, mTestUserContext);
|
||||
assertTrue(mUserChangeListener.userChanged == 1);
|
||||
assertTrue(mUserChangeListener.lastUserContext == mTestUserContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRemoveUserChangeListener_ensureNoCallback() {
|
||||
mController.addUserChangeListener(mUserChangeListener);
|
||||
mController.removeUserChangeListener(mUserChangeListener);
|
||||
|
||||
mController.onUserChanged(TEST_USER_ID, mTestUserContext);
|
||||
assertTrue(mUserChangeListener.userChanged == 0);
|
||||
assertTrue(mUserChangeListener.lastUserContext == null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserProfilesChanged() {
|
||||
mController.addUserChangeListener(mUserChangeListener);
|
||||
|
||||
ArrayList<UserInfo> profiles = new ArrayList<>();
|
||||
profiles.add(mock(UserInfo.class));
|
||||
profiles.add(mock(UserInfo.class));
|
||||
mController.onUserProfilesChanged(profiles);
|
||||
assertTrue(mUserChangeListener.lastUserProfiles.equals(profiles));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddKeyguardChangeListener_ensureCallback() {
|
||||
mController.addKeyguardChangeListener(mKeyguardChangeListener);
|
||||
@@ -332,4 +385,27 @@ public class ShellControllerTest extends ShellTestCase {
|
||||
dismissAnimationFinished++;
|
||||
}
|
||||
}
|
||||
|
||||
private class TestUserChangeListener implements UserChangeListener {
|
||||
// Counts of number of times each of the callbacks are called
|
||||
public int userChanged;
|
||||
public int lastUserId;
|
||||
public Context lastUserContext;
|
||||
public int userProfilesChanged;
|
||||
public List<? extends UserInfo> lastUserProfiles;
|
||||
|
||||
|
||||
@Override
|
||||
public void onUserChanged(int newUserId, @NonNull Context userContext) {
|
||||
userChanged++;
|
||||
lastUserId = newUserId;
|
||||
lastUserContext = userContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserProfilesChanged(@NonNull List<UserInfo> profiles) {
|
||||
userProfilesChanged++;
|
||||
lastUserProfiles = profiles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,6 @@ interface UserTracker : UserContentResolverProvider, UserContextProvider {
|
||||
* Notifies that the current user's profiles have changed.
|
||||
*/
|
||||
@JvmDefault
|
||||
fun onProfilesChanged(profiles: List<UserInfo>) {}
|
||||
fun onProfilesChanged(profiles: List<@JvmSuppressWildcards UserInfo>) {}
|
||||
}
|
||||
}
|
||||
@@ -29,14 +29,16 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_S
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.os.IBinder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||
import com.android.keyguard.KeyguardUpdateMonitorCallback;
|
||||
@@ -47,11 +49,11 @@ import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.keyguard.ScreenLifecycle;
|
||||
import com.android.systemui.keyguard.WakefulnessLifecycle;
|
||||
import com.android.systemui.model.SysUiState;
|
||||
import com.android.systemui.settings.UserTracker;
|
||||
import com.android.systemui.shared.tracing.ProtoTraceable;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.statusbar.policy.UserInfoController;
|
||||
import com.android.systemui.tracing.ProtoTracer;
|
||||
import com.android.systemui.tracing.nano.SystemUiTraceProto;
|
||||
import com.android.wm.shell.nano.WmShellTraceProto;
|
||||
@@ -66,6 +68,7 @@ import com.android.wm.shell.sysui.ShellInterface;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@@ -115,7 +118,7 @@ public final class WMShell extends CoreStartable
|
||||
private final SysUiState mSysUiState;
|
||||
private final WakefulnessLifecycle mWakefulnessLifecycle;
|
||||
private final ProtoTracer mProtoTracer;
|
||||
private final UserInfoController mUserInfoController;
|
||||
private final UserTracker mUserTracker;
|
||||
private final Executor mSysUiMainExecutor;
|
||||
|
||||
// Listeners and callbacks. Note that we prefer member variable over anonymous class here to
|
||||
@@ -144,9 +147,20 @@ public final class WMShell extends CoreStartable
|
||||
mShell.onKeyguardDismissAnimationFinished();
|
||||
}
|
||||
};
|
||||
private final UserTracker.Callback mUserChangedCallback =
|
||||
new UserTracker.Callback() {
|
||||
@Override
|
||||
public void onUserChanged(int newUser, @NonNull Context userContext) {
|
||||
mShell.onUserChanged(newUser, userContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProfilesChanged(@NonNull List<UserInfo> profiles) {
|
||||
mShell.onUserProfilesChanged(profiles);
|
||||
}
|
||||
};
|
||||
|
||||
private boolean mIsSysUiStateValid;
|
||||
private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback;
|
||||
private WakefulnessLifecycle.Observer mWakefulnessObserver;
|
||||
|
||||
@Inject
|
||||
@@ -163,7 +177,7 @@ public final class WMShell extends CoreStartable
|
||||
SysUiState sysUiState,
|
||||
ProtoTracer protoTracer,
|
||||
WakefulnessLifecycle wakefulnessLifecycle,
|
||||
UserInfoController userInfoController,
|
||||
UserTracker userTracker,
|
||||
@Main Executor sysUiMainExecutor) {
|
||||
super(context);
|
||||
mShell = shell;
|
||||
@@ -178,7 +192,7 @@ public final class WMShell extends CoreStartable
|
||||
mOneHandedOptional = oneHandedOptional;
|
||||
mWakefulnessLifecycle = wakefulnessLifecycle;
|
||||
mProtoTracer = protoTracer;
|
||||
mUserInfoController = userInfoController;
|
||||
mUserTracker = userTracker;
|
||||
mSysUiMainExecutor = sysUiMainExecutor;
|
||||
}
|
||||
|
||||
@@ -192,8 +206,9 @@ public final class WMShell extends CoreStartable
|
||||
mKeyguardStateController.addCallback(mKeyguardStateCallback);
|
||||
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
|
||||
|
||||
// TODO: Consider piping config change and other common calls to a shell component to
|
||||
// delegate internally
|
||||
// Subscribe to user changes
|
||||
mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor());
|
||||
|
||||
mProtoTracer.add(this);
|
||||
mCommandQueue.addCallback(this);
|
||||
mPipOptional.ifPresent(this::initPip);
|
||||
@@ -214,10 +229,6 @@ public final class WMShell extends CoreStartable
|
||||
mIsSysUiStateValid = (sysUiStateFlag & INVALID_SYSUI_STATE_MASK) == 0;
|
||||
pip.onSystemUiStateChanged(mIsSysUiStateValid, sysUiStateFlag);
|
||||
});
|
||||
|
||||
// The media session listener needs to be re-registered when switching users
|
||||
mUserInfoController.addCallback((String name, Drawable picture, String userAccount) ->
|
||||
pip.registerSessionListenerForCurrentUser());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -267,15 +278,6 @@ 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 onUserSwitchComplete(int userId) {
|
||||
oneHanded.onUserSwitch(userId);
|
||||
}
|
||||
};
|
||||
mKeyguardUpdateMonitor.registerCallback(mOneHandedKeyguardCallback);
|
||||
|
||||
mWakefulnessObserver =
|
||||
new WakefulnessLifecycle.Observer() {
|
||||
@Override
|
||||
|
||||
@@ -28,10 +28,10 @@ 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.settings.UserTracker;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.statusbar.policy.UserInfoController;
|
||||
import com.android.systemui.tracing.ProtoTracer;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.onehanded.OneHanded;
|
||||
@@ -72,7 +72,7 @@ public class WMShellTest extends SysuiTestCase {
|
||||
@Mock OneHanded mOneHanded;
|
||||
@Mock WakefulnessLifecycle mWakefulnessLifecycle;
|
||||
@Mock ProtoTracer mProtoTracer;
|
||||
@Mock UserInfoController mUserInfoController;
|
||||
@Mock UserTracker mUserTracker;
|
||||
@Mock ShellExecutor mSysUiMainExecutor;
|
||||
|
||||
@Before
|
||||
@@ -83,7 +83,7 @@ public class WMShellTest extends SysuiTestCase {
|
||||
Optional.of(mSplitScreen), Optional.of(mOneHanded), mCommandQueue,
|
||||
mConfigurationController, mKeyguardStateController, mKeyguardUpdateMonitor,
|
||||
mScreenLifecycle, mSysUiState, mProtoTracer, mWakefulnessLifecycle,
|
||||
mUserInfoController, mSysUiMainExecutor);
|
||||
mUserTracker, mSysUiMainExecutor);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user