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:
Winson Chung
2022-08-19 05:56:47 +00:00
parent 3234afdaf3
commit c1dc8c8755
16 changed files with 300 additions and 78 deletions

View File

@@ -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,

View File

@@ -80,9 +80,4 @@ public interface OneHanded {
* transition start or finish
*/
void registerTransitionCallback(OneHandedTransitionCallback callback);
/**
* Notifies when user switch complete
*/
void onUserSwitch(int userId);
}

View File

@@ -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);
});
}
}
/**

View File

@@ -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.
*

View File

@@ -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(() -> {

View File

@@ -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
}
}

View File

@@ -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.

View File

@@ -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));
}
}
}

View File

@@ -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) {}
}

View File

@@ -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) {}
}

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -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;
}
}
}

View File

@@ -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>) {}
}
}

View File

@@ -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

View File

@@ -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