diff options
26 files changed, 359 insertions, 346 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index d6f4d6daaa83..ead0bcd15c73 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -267,9 +267,6 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { return; } sendStatusChanged(); - } else { - throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo - + "\n mRootTaskInfo: " + mRootTaskInfo); } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java index 5ee8bf3006a3..b31e20fcc438 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java @@ -126,12 +126,6 @@ public final class StageTaskListenerTests extends ShellTestCase { verify(mCallbacks).onStatusChanged(eq(mRootTask.isVisible), eq(true)); } - @Test(expected = IllegalArgumentException.class) - public void testUnknownTaskVanished() { - final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build(); - mStageTaskListener.onTaskVanished(task); - } - @Test public void testTaskVanished() { // With shell transitions, the transition manages status changes, so skip this test. diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java index 3125f088c72b..0e67ff58b1cf 100644 --- a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java +++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java @@ -72,7 +72,6 @@ public final class LowLightDreamManager { public static final int AMBIENT_LIGHT_MODE_LOW_LIGHT = 2; private final DreamManager mDreamManager; - private final LowLightTransitionCoordinator mLowLightTransitionCoordinator; @Nullable private final ComponentName mLowLightDreamComponent; @@ -82,10 +81,8 @@ public final class LowLightDreamManager { @Inject public LowLightDreamManager( DreamManager dreamManager, - LowLightTransitionCoordinator lowLightTransitionCoordinator, @Named(LOW_LIGHT_DREAM_COMPONENT) @Nullable ComponentName lowLightDreamComponent) { mDreamManager = dreamManager; - mLowLightTransitionCoordinator = lowLightTransitionCoordinator; mLowLightDreamComponent = lowLightDreamComponent; } @@ -115,8 +112,6 @@ public final class LowLightDreamManager { mAmbientLightMode = ambientLightMode; boolean shouldEnterLowLight = mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT; - mLowLightTransitionCoordinator.notifyBeforeLowLightTransition(shouldEnterLowLight, - () -> mDreamManager.setSystemDreamComponent( - shouldEnterLowLight ? mLowLightDreamComponent : null)); + mDreamManager.setSystemDreamComponent(shouldEnterLowLight ? mLowLightDreamComponent : null); } } diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java index 4b95d8c84bac..f860613fc469 100644 --- a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java +++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java @@ -21,10 +21,7 @@ import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_UNKNOWN; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -47,9 +44,6 @@ public class LowLightDreamManagerTest { private DreamManager mDreamManager; @Mock - private LowLightTransitionCoordinator mTransitionCoordinator; - - @Mock private ComponentName mDreamComponent; LowLightDreamManager mLowLightDreamManager; @@ -58,14 +52,7 @@ public class LowLightDreamManagerTest { public void setUp() { MockitoAnnotations.initMocks(this); - // Automatically run any provided Runnable to mTransitionCoordinator to simplify testing. - doAnswer(invocation -> { - ((Runnable) invocation.getArgument(1)).run(); - return null; - }).when(mTransitionCoordinator).notifyBeforeLowLightTransition(anyBoolean(), - any(Runnable.class)); - - mLowLightDreamManager = new LowLightDreamManager(mDreamManager, mTransitionCoordinator, + mLowLightDreamManager = new LowLightDreamManager(mDreamManager, mDreamComponent); } @@ -73,7 +60,6 @@ public class LowLightDreamManagerTest { public void setAmbientLightMode_lowLight_setSystemDream() { mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT); - verify(mTransitionCoordinator).notifyBeforeLowLightTransition(eq(true), any()); verify(mDreamManager).setSystemDreamComponent(mDreamComponent); } @@ -81,7 +67,6 @@ public class LowLightDreamManagerTest { public void setAmbientLightMode_regularLight_clearSystemDream() { mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_REGULAR); - verify(mTransitionCoordinator).notifyBeforeLowLightTransition(eq(false), any()); verify(mDreamManager).setSystemDreamComponent(null); } @@ -100,7 +85,7 @@ public class LowLightDreamManagerTest { @Test public void setAmbientLightMode_dreamComponentNotSet_doNothing() { final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager, - mTransitionCoordinator, null /*dream component*/); + null /*dream component*/); lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT); diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index cacf13326178..5c369afc1fcd 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -893,18 +893,6 @@ android:visibleToInstantApps="true"> </activity> - <activity android:name=".user.UserSwitcherActivity" - android:label="@string/accessibility_multi_user_switch_switcher" - android:theme="@style/Theme.UserSwitcherActivity" - android:excludeFromRecents="true" - android:showWhenLocked="true" - android:showForAllUsers="true" - android:finishOnTaskLaunch="true" - android:lockTaskMode="always" - android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden" - android:visibleToInstantApps="true"> - </activity> - <receiver android:name=".controls.management.ControlsRequestReceiver" android:exported="true"> <intent-filter> diff --git a/packages/SystemUI/docs/user-switching.md b/packages/SystemUI/docs/user-switching.md index b9509eb41c3c..01cba426f782 100644 --- a/packages/SystemUI/docs/user-switching.md +++ b/packages/SystemUI/docs/user-switching.md @@ -6,7 +6,7 @@ Multiple users and the ability to switch between them is controlled by Settings ### Quick Settings -In the QS footer, an icon becomes available for users to tap on. The view and its onClick actions are handled by [MultiUserSwitchController][2]. Multiple visual implementations are currently in use; one for phones/foldables ([UserSwitchDialogController][6]) and one for tablets ([UserSwitcherActivity][5]). +In the QS footer, an icon becomes available for users to tap on. The view and its onClick actions are handled by [MultiUserSwitchController][2]. Multiple visual implementations are currently in use; one for phones/foldables ([UserSwitchDialogController][6]) and one for tablets ([UserSwitcherFullscreenDialog][5]). ### Bouncer @@ -29,7 +29,7 @@ All visual implementations should derive their logic and use the adapter specifi ## Visual Components -### [UserSwitcherActivity][5] +### [UserSwitcherFullscreenDialog][5] A fullscreen user switching activity, supporting add guest/user actions if configured. @@ -41,5 +41,5 @@ Renders user switching as a dialog over the current surface, and supports add gu [2]: /frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserController.java [3]: /frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java [4]: /frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java -[5]: /frameworks/base/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt +[5]: /frameworks/base/packages/SystemUI/src/com/android/systemui/user/UserSwitcherFullscreenDialog.kt [6]: /frameworks/base/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 1da1a294f9ba..27b15c926bbb 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -836,12 +836,10 @@ <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item> </style> - <style name="Theme.UserSwitcherActivity" parent="@android:style/Theme.DeviceDefault.NoActionBar"> + <style name="Theme.UserSwitcherFullscreenDialog" parent="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen"> <item name="android:statusBarColor">@color/user_switcher_fullscreen_bg</item> <item name="android:windowBackground">@color/user_switcher_fullscreen_bg</item> <item name="android:navigationBarColor">@color/user_switcher_fullscreen_bg</item> - <!-- Setting a placeholder will avoid using the SystemUI icon on the splash screen --> - <item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item> </style> <style name="Theme.CreateUser" parent="@android:style/Theme.DeviceDefault.NoActionBar"> diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt index 8387c1dd60a5..b394a079fb00 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt @@ -89,7 +89,7 @@ interface FooterActionsInteractor { fun showSettings(expandable: Expandable) /** Show the user switcher. */ - fun showUserSwitcher(context: Context, expandable: Expandable) + fun showUserSwitcher(expandable: Expandable) } @SysUISingleton @@ -177,7 +177,7 @@ constructor( ) } - override fun showUserSwitcher(context: Context, expandable: Expandable) { - userInteractor.showUserSwitcher(context, expandable) + override fun showUserSwitcher(expandable: Expandable) { + userInteractor.showUserSwitcher(expandable) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt index f170ac1d9d4e..3a9098ab49d3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt @@ -230,7 +230,7 @@ class FooterActionsViewModel( return } - footerActionsInteractor.showUserSwitcher(context, expandable) + footerActionsInteractor.showUserSwitcher(expandable) } private fun onSettingsButtonClicked(expandable: Expandable) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index ced725e0b1d6..89e48831a96b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -26,10 +26,12 @@ import android.annotation.Nullable; import android.app.Notification; import android.content.Context; import android.graphics.Bitmap; +import android.graphics.Point; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; +import android.hardware.display.DisplayManager; import android.media.MediaMetadata; import android.media.session.MediaController; import android.media.session.MediaSession; @@ -40,6 +42,7 @@ import android.service.notification.NotificationStats; import android.service.notification.StatusBarNotification; import android.util.ArraySet; import android.util.Log; +import android.view.Display; import android.view.View; import android.widget.ImageView; @@ -72,11 +75,15 @@ import com.android.systemui.util.concurrency.DelayableExecutor; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Comparator; import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import dagger.Lazy; @@ -134,6 +141,14 @@ public class NotificationMediaManager implements Dumpable { private BackDropView mBackdrop; private ImageView mBackdropFront; private ImageView mBackdropBack; + private final Point mTmpDisplaySize = new Point(); + + private final DisplayManager mDisplayManager; + @Nullable + private List<String> mSmallerInternalDisplayUids; + private Display mCurrentDisplay; + + private LockscreenWallpaper.WallpaperDrawable mWallapperDrawable; private final MediaController.Callback mMediaListener = new MediaController.Callback() { @Override @@ -179,7 +194,8 @@ public class NotificationMediaManager implements Dumpable { StatusBarStateController statusBarStateController, SysuiColorExtractor colorExtractor, KeyguardStateController keyguardStateController, - DumpManager dumpManager) { + DumpManager dumpManager, + DisplayManager displayManager) { mContext = context; mMediaArtworkProcessor = mediaArtworkProcessor; mKeyguardBypassController = keyguardBypassController; @@ -195,6 +211,7 @@ public class NotificationMediaManager implements Dumpable { mStatusBarStateController = statusBarStateController; mColorExtractor = colorExtractor; mKeyguardStateController = keyguardStateController; + mDisplayManager = displayManager; setupNotifPipeline(); @@ -471,6 +488,48 @@ public class NotificationMediaManager implements Dumpable { } /** + * Notify lockscreen wallpaper drawable the current internal display. + */ + public void onDisplayUpdated(Display display) { + Trace.beginSection("NotificationMediaManager#onDisplayUpdated"); + mCurrentDisplay = display; + if (mWallapperDrawable != null) { + mWallapperDrawable.onDisplayUpdated(isOnSmallerInternalDisplays()); + } + Trace.endSection(); + } + + private boolean isOnSmallerInternalDisplays() { + if (mSmallerInternalDisplayUids == null) { + mSmallerInternalDisplayUids = findSmallerInternalDisplayUids(); + } + return mSmallerInternalDisplayUids.contains(mCurrentDisplay.getUniqueId()); + } + + private List<String> findSmallerInternalDisplayUids() { + if (mSmallerInternalDisplayUids != null) { + return mSmallerInternalDisplayUids; + } + List<Display> internalDisplays = Arrays.stream(mDisplayManager.getDisplays( + DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) + .filter(display -> display.getType() == Display.TYPE_INTERNAL) + .collect(Collectors.toList()); + if (internalDisplays.isEmpty()) { + return List.of(); + } + Display largestDisplay = internalDisplays.stream() + .max(Comparator.comparingInt(this::getRealDisplayArea)) + .orElse(internalDisplays.get(0)); + internalDisplays.remove(largestDisplay); + return internalDisplays.stream().map(Display::getUniqueId).collect(Collectors.toList()); + } + + private int getRealDisplayArea(Display display) { + display.getRealSize(mTmpDisplaySize); + return mTmpDisplaySize.x * mTmpDisplaySize.y; + } + + /** * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper. */ public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) { @@ -542,7 +601,7 @@ public class NotificationMediaManager implements Dumpable { mLockscreenWallpaper != null ? mLockscreenWallpaper.getBitmap() : null; if (lockWallpaper != null) { artworkDrawable = new LockscreenWallpaper.WallpaperDrawable( - mBackdropBack.getResources(), lockWallpaper); + mBackdropBack.getResources(), lockWallpaper, isOnSmallerInternalDisplays()); // We're in the SHADE mode on the SIM screen - yet we still need to show // the lockscreen wallpaper in that mode. allowWhenShade = mStatusBarStateController.getState() == KEYGUARD; @@ -602,6 +661,10 @@ public class NotificationMediaManager implements Dumpable { mBackdropBack.setBackgroundColor(0xFFFFFFFF); mBackdropBack.setImageDrawable(new ColorDrawable(c)); } else { + if (artworkDrawable instanceof LockscreenWallpaper.WallpaperDrawable) { + mWallapperDrawable = + (LockscreenWallpaper.WallpaperDrawable) artworkDrawable; + } mBackdropBack.setImageDrawable(artworkDrawable); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java index d7568a9bd89c..4afa21e83f08 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.dagger; import android.app.IActivityManager; import android.content.Context; +import android.hardware.display.DisplayManager; import android.os.RemoteException; import android.service.dreams.IDreamManager; import android.util.Log; @@ -139,7 +140,8 @@ public interface CentralSurfacesDependenciesModule { StatusBarStateController statusBarStateController, SysuiColorExtractor colorExtractor, KeyguardStateController keyguardStateController, - DumpManager dumpManager) { + DumpManager dumpManager, + DisplayManager displayManager) { return new NotificationMediaManager( context, centralSurfacesOptionalLazy, @@ -154,7 +156,8 @@ public interface CentralSurfacesDependenciesModule { statusBarStateController, colorExtractor, keyguardStateController, - dumpManager); + dumpManager, + displayManager); } /** */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 56e2dc460234..de129a3a2eb4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -2311,6 +2311,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { void updateDisplaySize() { mDisplay.getMetrics(mDisplayMetrics); mDisplay.getSize(mCurrentDisplaySize); + mMediaManager.onDisplayUpdated(mDisplay); if (DEBUG_GESTURES) { mGestureRec.tag("display", String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java index 1d7dfe199871..b3b66a7635d9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java @@ -259,19 +259,25 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen /** * Drawable that aligns left horizontally and center vertically (like ImageWallpaper). + * + * <p>Aligns to the center when showing on the smaller internal display of a multi display + * device. */ public static class WallpaperDrawable extends DrawableWrapper { private final ConstantState mState; private final Rect mTmpRect = new Rect(); + private boolean mIsOnSmallerInternalDisplays; - public WallpaperDrawable(Resources r, Bitmap b) { - this(r, new ConstantState(b)); + public WallpaperDrawable(Resources r, Bitmap b, boolean isOnSmallerInternalDisplays) { + this(r, new ConstantState(b), isOnSmallerInternalDisplays); } - private WallpaperDrawable(Resources r, ConstantState state) { + private WallpaperDrawable(Resources r, ConstantState state, + boolean isOnSmallerInternalDisplays) { super(new BitmapDrawable(r, state.mBackground)); mState = state; + mIsOnSmallerInternalDisplays = isOnSmallerInternalDisplays; } @Override @@ -310,10 +316,17 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen } dy = (vheight - dheight * scale) * 0.5f; + int offsetX = 0; + // Offset to show the center area of the wallpaper on a smaller display for multi + // display device + if (mIsOnSmallerInternalDisplays) { + offsetX = bounds.centerX() - (Math.round(dwidth * scale) / 2); + } + mTmpRect.set( - bounds.left, + bounds.left + offsetX, bounds.top + Math.round(dy), - bounds.left + Math.round(dwidth * scale), + bounds.left + Math.round(dwidth * scale) + offsetX, bounds.top + Math.round(dheight * scale + dy)); super.onBoundsChange(mTmpRect); @@ -324,6 +337,17 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen return mState; } + /** + * Update bounds when the hosting display or the display size has changed. + * + * @param isOnSmallerInternalDisplays tru if the drawable is on one of the internal displays + * with the smaller area. + */ + public void onDisplayUpdated(boolean isOnSmallerInternalDisplays) { + mIsOnSmallerInternalDisplays = isOnSmallerInternalDisplays; + onBoundsChange(getBounds()); + } + static class ConstantState extends Drawable.ConstantState { private final Bitmap mBackground; @@ -339,7 +363,7 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen @Override public Drawable newDrawable(@Nullable Resources res) { - return new WallpaperDrawable(res, this); + return new WallpaperDrawable(res, this, /* isOnSmallerInternalDisplays= */ false); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/user/UserModule.java b/packages/SystemUI/src/com/android/systemui/user/UserModule.java index f7c8bac1b478..b2bf9727b534 100644 --- a/packages/SystemUI/src/com/android/systemui/user/UserModule.java +++ b/packages/SystemUI/src/com/android/systemui/user/UserModule.java @@ -16,7 +16,6 @@ package com.android.systemui.user; -import android.app.Activity; import android.os.UserHandle; import com.android.settingslib.users.EditUserInfoController; @@ -24,11 +23,8 @@ import com.android.systemui.user.data.repository.UserRepositoryModule; import com.android.systemui.user.domain.interactor.HeadlessSystemUserModeModule; import com.android.systemui.user.ui.dialog.UserDialogModule; -import dagger.Binds; import dagger.Module; import dagger.Provides; -import dagger.multibindings.ClassKey; -import dagger.multibindings.IntoMap; /** * Dagger module for User related classes. @@ -49,12 +45,6 @@ public abstract class UserModule { return new EditUserInfoController(FILE_PROVIDER_AUTHORITY); } - /** Provides UserSwitcherActivity */ - @Binds - @IntoMap - @ClassKey(UserSwitcherActivity.class) - public abstract Activity provideUserSwitcherActivity(UserSwitcherActivity activity); - /** * Provides the {@link UserHandle} for the user associated with this System UI process. * diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt deleted file mode 100644 index 52b7fb63c1a2..000000000000 --- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.systemui.user - -import android.os.Bundle -import android.view.WindowInsets.Type -import android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE -import androidx.activity.ComponentActivity -import androidx.lifecycle.ViewModelProvider -import com.android.systemui.R -import com.android.systemui.classifier.FalsingCollector -import com.android.systemui.user.ui.binder.UserSwitcherViewBinder -import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel -import dagger.Lazy -import javax.inject.Inject - -/** Support a fullscreen user switcher */ -open class UserSwitcherActivity -@Inject -constructor( - private val falsingCollector: FalsingCollector, - private val viewModelFactory: Lazy<UserSwitcherViewModel.Factory>, -) : ComponentActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.user_switcher_fullscreen) - window.decorView.windowInsetsController?.let { controller -> - controller.systemBarsBehavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE - controller.hide(Type.systemBars()) - } - val viewModel = - ViewModelProvider(this, viewModelFactory.get())[UserSwitcherViewModel::class.java] - UserSwitcherViewBinder.bind( - view = requireViewById(R.id.user_switcher_root), - viewModel = viewModel, - lifecycleOwner = this, - layoutInflater = layoutInflater, - falsingCollector = falsingCollector, - onFinish = this::finish, - ) - } -} diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherFullscreenDialog.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherFullscreenDialog.kt new file mode 100644 index 000000000000..72786efc416d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherFullscreenDialog.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2023 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.systemui.user + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.view.WindowInsets +import android.view.WindowInsetsController +import com.android.systemui.R +import com.android.systemui.classifier.FalsingCollector +import com.android.systemui.statusbar.phone.SystemUIDialog +import com.android.systemui.user.ui.binder.UserSwitcherViewBinder +import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel + +class UserSwitchFullscreenDialog( + context: Context, + private val falsingCollector: FalsingCollector, + private val userSwitcherViewModel: UserSwitcherViewModel, +) : SystemUIDialog(context, R.style.Theme_UserSwitcherFullscreenDialog) { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setShowForAllUsers(true) + setCanceledOnTouchOutside(true) + + window?.decorView?.windowInsetsController?.let { controller -> + controller.systemBarsBehavior = + WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + controller.hide(WindowInsets.Type.systemBars()) + } + + val view = + LayoutInflater.from(this.context).inflate(R.layout.user_switcher_fullscreen, null) + setContentView(view) + + UserSwitcherViewBinder.bind( + view = requireViewById(R.id.user_switcher_root), + viewModel = userSwitcherViewModel, + layoutInflater = layoutInflater, + falsingCollector = falsingCollector, + onFinish = this::dismiss, + ) + } + + override fun getWidth(): Int { + val displayMetrics = context.resources.displayMetrics.apply { + context.display.getRealMetrics(this) + } + return displayMetrics.widthPixels + } + + override fun getHeight() = MATCH_PARENT + +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt index 02d447976746..667a3ca8f9d2 100644 --- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt @@ -48,7 +48,6 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.user.UserSwitchDialogController import com.android.systemui.telephony.domain.interactor.TelephonyInteractor -import com.android.systemui.user.UserSwitcherActivity import com.android.systemui.user.data.model.UserSwitcherSettingsModel import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.user.data.source.UserRecord @@ -502,24 +501,12 @@ constructor( } } - fun showUserSwitcher(context: Context, expandable: Expandable) { - if (!featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) { + fun showUserSwitcher(expandable: Expandable) { + if (featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) { + showDialog(ShowDialogRequestModel.ShowUserSwitcherFullscreenDialog(expandable)) + } else { showDialog(ShowDialogRequestModel.ShowUserSwitcherDialog(expandable)) - return } - - val intent = - Intent(context, UserSwitcherActivity::class.java).apply { - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) - } - - activityStarter.startActivity( - intent, - true /* dismissShade */, - expandable.activityLaunchController(), - true /* showOverlockscreenwhenlocked */, - UserHandle.SYSTEM, - ) } private fun showDialog(request: ShowDialogRequestModel) { diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.kt b/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.kt index 14cc3e783fed..de73cdbb6026 100644 --- a/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.kt +++ b/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.kt @@ -50,4 +50,8 @@ sealed class ShowDialogRequestModel( data class ShowUserSwitcherDialog( override val expandable: Expandable?, ) : ShowDialogRequestModel() + + data class ShowUserSwitcherFullscreenDialog( + override val expandable: Expandable?, + ) : ShowDialogRequestModel() } diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt index e13710786fbb..7236e0fd134a 100644 --- a/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt @@ -31,19 +31,18 @@ import android.widget.TextView import androidx.constraintlayout.helper.widget.Flow as FlowWidget import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.Gefingerpoken import com.android.systemui.R import com.android.systemui.classifier.FalsingCollector +import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.user.UserSwitcherPopupMenu import com.android.systemui.user.UserSwitcherRootView import com.android.systemui.user.shared.model.UserActionModel import com.android.systemui.user.ui.viewmodel.UserActionViewModel import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel import com.android.systemui.util.children -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch @@ -56,7 +55,6 @@ object UserSwitcherViewBinder { fun bind( view: ViewGroup, viewModel: UserSwitcherViewModel, - lifecycleOwner: LifecycleOwner, layoutInflater: LayoutInflater, falsingCollector: FalsingCollector, onFinish: () -> Unit, @@ -79,88 +77,92 @@ object UserSwitcherViewBinder { addButton.setOnClickListener { viewModel.onOpenMenuButtonClicked() } cancelButton.setOnClickListener { viewModel.onCancelButtonClicked() } - lifecycleOwner.lifecycleScope.launch { - lifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) { - launch { - viewModel.isFinishRequested - .filter { it } - .collect { - onFinish() - viewModel.onFinished() - } + view.repeatWhenAttached { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.CREATED) { + launch { + viewModel.isFinishRequested + .filter { it } + .collect { + //finish requested, we want to dismiss popupmenu at the same time + popupMenu?.dismiss() + onFinish() + viewModel.onFinished() + } + } } } - } - lifecycleOwner.lifecycleScope.launch { - lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { - launch { viewModel.isOpenMenuButtonVisible.collect { addButton.isVisible = it } } - - launch { - viewModel.isMenuVisible.collect { isVisible -> - if (isVisible && popupMenu?.isShowing != true) { - popupMenu?.dismiss() - // Use post to make sure we show the popup menu *after* the activity is - // ready to show one to avoid a WindowManager$BadTokenException. - view.post { - popupMenu = - createAndShowPopupMenu( - context = view.context, - anchorView = addButton, - adapter = popupMenuAdapter, - onDismissed = viewModel::onMenuClosed, - ) + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { viewModel.isOpenMenuButtonVisible.collect { addButton.isVisible = it } } + + launch { + viewModel.isMenuVisible.collect { isVisible -> + if (isVisible && popupMenu?.isShowing != true) { + popupMenu?.dismiss() + // Use post to make sure we show the popup menu *after* the activity is + // ready to show one to avoid a WindowManager$BadTokenException. + view.post { + popupMenu = + createAndShowPopupMenu( + context = view.context, + anchorView = addButton, + adapter = popupMenuAdapter, + onDismissed = viewModel::onMenuClosed, + ) + } + } else if (!isVisible && popupMenu?.isShowing == true) { + popupMenu?.dismiss() + popupMenu = null } - } else if (!isVisible && popupMenu?.isShowing == true) { - popupMenu?.dismiss() - popupMenu = null } } - } - launch { - viewModel.menu.collect { menuViewModels -> - popupMenuAdapter.setItems(menuViewModels) + launch { + viewModel.menu.collect { menuViewModels -> + popupMenuAdapter.setItems(menuViewModels) + } } - } - launch { - viewModel.maximumUserColumns.collect { maximumColumns -> - flowWidget.setMaxElementsWrap(maximumColumns) + launch { + viewModel.maximumUserColumns.collect { maximumColumns -> + flowWidget.setMaxElementsWrap(maximumColumns) + } } - } - launch { - viewModel.users.collect { users -> - val viewPool = - gridContainerView.children - .filter { it.tag == USER_VIEW_TAG } - .toMutableList() - viewPool.forEach { - gridContainerView.removeView(it) - flowWidget.removeView(it) - } - users.forEach { userViewModel -> - val userView = - if (viewPool.isNotEmpty()) { - viewPool.removeAt(0) - } else { - val inflatedView = - layoutInflater.inflate( - R.layout.user_switcher_fullscreen_item, - view, - false, - ) - inflatedView.tag = USER_VIEW_TAG - inflatedView - } - userView.id = View.generateViewId() - gridContainerView.addView(userView) - flowWidget.addView(userView) - UserViewBinder.bind( - view = userView, - viewModel = userViewModel, - ) + launch { + viewModel.users.collect { users -> + val viewPool = + gridContainerView.children + .filter { it.tag == USER_VIEW_TAG } + .toMutableList() + viewPool.forEach { + gridContainerView.removeView(it) + flowWidget.removeView(it) + } + users.forEach { userViewModel -> + val userView = + if (viewPool.isNotEmpty()) { + viewPool.removeAt(0) + } else { + val inflatedView = + layoutInflater.inflate( + R.layout.user_switcher_fullscreen_item, + view, + false, + ) + inflatedView.tag = USER_VIEW_TAG + inflatedView + } + userView.id = View.generateViewId() + gridContainerView.addView(userView) + flowWidget.addView(userView) + UserViewBinder.bind( + view = userView, + viewModel = userViewModel, + ) + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt index 79721b370c21..0930cb8a3d7a 100644 --- a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt @@ -26,13 +26,16 @@ import com.android.systemui.CoreStartable import com.android.systemui.animation.DialogCuj import com.android.systemui.animation.DialogLaunchAnimator import com.android.systemui.broadcast.BroadcastSender +import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.qs.tiles.UserDetailView +import com.android.systemui.user.UserSwitchFullscreenDialog import com.android.systemui.user.domain.interactor.UserInteractor import com.android.systemui.user.domain.model.ShowDialogRequestModel +import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel import dagger.Lazy import javax.inject.Inject import javax.inject.Provider @@ -54,6 +57,8 @@ constructor( private val userDetailAdapterProvider: Provider<UserDetailView.Adapter>, private val eventLogger: Lazy<UiEventLogger>, private val activityStarter: Lazy<ActivityStarter>, + private val falsingCollector: Lazy<FalsingCollector>, + private val userSwitcherViewModel: Lazy<UserSwitcherViewModel>, ) : CoreStartable { private var currentDialog: Dialog? = null @@ -124,6 +129,15 @@ constructor( INTERACTION_JANK_EXIT_GUEST_MODE_TAG, ), ) + is ShowDialogRequestModel.ShowUserSwitcherFullscreenDialog -> + Pair( + UserSwitchFullscreenDialog( + context = context.get(), + falsingCollector = falsingCollector.get(), + userSwitcherViewModel = userSwitcherViewModel.get(), + ), + null, /* dialogCuj */ + ) } currentDialog = dialog diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModel.kt index 3300e8e5b2a5..78edad7c3af2 100644 --- a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModel.kt @@ -55,5 +55,5 @@ constructor( interactor.selectedUser.mapLatest { userModel -> userModel.image } /** Action to execute on click. Should launch the user switcher */ - val onClick: (Expandable) -> Unit = { interactor.showUserSwitcher(context, it) } + val onClick: (Expandable) -> Unit = { interactor.showUserSwitcher(it) } } diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt index 37115ad53880..afd72e7ed1be 100644 --- a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt @@ -17,12 +17,10 @@ package com.android.systemui.user.ui.viewmodel -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import com.android.systemui.R import com.android.systemui.common.shared.model.Text import com.android.systemui.common.ui.drawable.CircularDrawable -import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.user.domain.interactor.GuestUserInteractor import com.android.systemui.user.domain.interactor.UserInteractor import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper @@ -36,12 +34,13 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map /** Models UI state for the user switcher feature. */ +@SysUISingleton class UserSwitcherViewModel -private constructor( +@Inject +constructor( private val userInteractor: UserInteractor, private val guestUserInteractor: GuestUserInteractor, - private val powerInteractor: PowerInteractor, -) : ViewModel() { +) { /** On-device users. */ val users: Flow<List<UserViewModel>> = @@ -112,34 +111,15 @@ private constructor( } } - private fun createFinishRequestedFlow(): Flow<Boolean> { - var mostRecentSelectedUserId: Int? = null - var mostRecentIsInteractive: Boolean? = null - - return combine( - // When the user is switched, we should finish. - userInteractor.selectedUser - .map { it.id } - .map { - val selectedUserChanged = - mostRecentSelectedUserId != null && mostRecentSelectedUserId != it - mostRecentSelectedUserId = it - selectedUserChanged - }, - // When the screen turns off, we should finish. - powerInteractor.isInteractive.map { - val screenTurnedOff = mostRecentIsInteractive == true && !it - mostRecentIsInteractive = it - screenTurnedOff - }, + private fun createFinishRequestedFlow(): Flow<Boolean> = + combine( // When the cancel button is clicked, we should finish. hasCancelButtonBeenClicked, // If an executed action told us to finish, we should finish, isFinishRequiredDueToExecutedAction, - ) { selectedUserChanged, screenTurnedOff, cancelButtonClicked, executedActionFinish -> - selectedUserChanged || screenTurnedOff || cancelButtonClicked || executedActionFinish + ) { cancelButtonClicked, executedActionFinish -> + cancelButtonClicked || executedActionFinish } - } private fun toViewModel( model: UserModel, @@ -210,22 +190,4 @@ private constructor( { userInteractor.selectUser(model.id) } } } - - class Factory - @Inject - constructor( - private val userInteractor: UserInteractor, - private val guestUserInteractor: GuestUserInteractor, - private val powerInteractor: PowerInteractor, - ) : ViewModelProvider.Factory { - override fun <T : ViewModel> create(modelClass: Class<T>): T { - @Suppress("UNCHECKED_CAST") - return UserSwitcherViewModel( - userInteractor = userInteractor, - guestUserInteractor = guestUserInteractor, - powerInteractor = powerInteractor, - ) - as T - } - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenWallpaperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenWallpaperTest.kt new file mode 100644 index 000000000000..fece5bad970a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenWallpaperTest.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023 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.systemui.statusbar.phone + +import android.graphics.Bitmap +import android.graphics.Rect +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class LockscreenWallpaperTest : SysuiTestCase() { + + @Test + fun testLockscreenWallpaper_onSmallerInternalDisplay_centerAlignsDrawable() { + val displaySize = Rect(0, 0, 1080, 2092) + val wallpaperDrawable = + LockscreenWallpaper.WallpaperDrawable( + context.resources, + Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888), + /* isOnSmallerInternalDisplays= */ false + ) + .apply { bounds = displaySize } + + wallpaperDrawable.onDisplayUpdated(true) + + assertThat(wallpaperDrawable.drawable.bounds.centerX()) + .isEqualTo(wallpaperDrawable.bounds.centerX()) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt index 3ed6cc88826c..e3b8649718c1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.user.domain.interactor import android.app.ActivityManager import android.app.admin.DevicePolicyManager -import android.content.ComponentName import android.content.Intent import android.content.pm.UserInfo import android.graphics.Bitmap @@ -49,7 +48,6 @@ import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.telephony.data.repository.FakeTelephonyRepository import com.android.systemui.telephony.domain.interactor.TelephonyInteractor -import com.android.systemui.user.UserSwitcherActivity import com.android.systemui.user.data.model.UserSwitcherSettingsModel import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.source.UserRecord @@ -57,11 +55,9 @@ import com.android.systemui.user.domain.model.ShowDialogRequestModel import com.android.systemui.user.shared.model.UserActionModel import com.android.systemui.user.shared.model.UserModel import com.android.systemui.util.mockito.any -import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.kotlinArgumentCaptor import com.android.systemui.util.mockito.mock -import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertNotNull @@ -800,7 +796,7 @@ class UserInteractorTest : SysuiTestCase() { fun `show user switcher - full screen disabled - shows dialog switcher`() = testScope.runTest { val expandable = mock<Expandable>() - underTest.showUserSwitcher(context, expandable) + underTest.showUserSwitcher(expandable) val dialogRequest = collectLastValue(underTest.dialogShowRequests) @@ -813,30 +809,22 @@ class UserInteractorTest : SysuiTestCase() { } @Test - fun `show user switcher - full screen enabled - launches activity`() { - featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true) - - val expandable = mock<Expandable>() - underTest.showUserSwitcher(context, expandable) - - // Dialog is shown. - val intentCaptor = argumentCaptor<Intent>() - verify(activityStarter) - .startActivity( - intentCaptor.capture(), - /* dismissShade= */ eq(true), - /* ActivityLaunchAnimator.Controller= */ nullable(), - /* showOverLockscreenWhenLocked= */ eq(true), - eq(UserHandle.SYSTEM), - ) - assertThat(intentCaptor.value.component) - .isEqualTo( - ComponentName( - context, - UserSwitcherActivity::class.java, - ) - ) - } + fun `show user switcher - full screen enabled - launches full screen dialog`() = + testScope.runTest { + featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true) + + val expandable = mock<Expandable>() + underTest.showUserSwitcher(expandable) + + val dialogRequest = collectLastValue(underTest.dialogShowRequests) + + // Dialog is shown. + assertThat(dialogRequest()) + .isEqualTo(ShowDialogRequestModel.ShowUserSwitcherFullscreenDialog(expandable)) + + underTest.onDialogShown() + assertThat(dialogRequest()).isNull() + } @Test fun `users - secondary user - managed profile is not included`() = diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt index e08ebf4a9050..5cd2df99325b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt @@ -34,8 +34,6 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerReposito import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.power.data.repository.FakePowerRepository -import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.telephony.data.repository.FakeTelephonyRepository @@ -88,7 +86,6 @@ class UserSwitcherViewModelTest : SysuiTestCase() { private lateinit var userRepository: FakeUserRepository private lateinit var keyguardRepository: FakeKeyguardRepository - private lateinit var powerRepository: FakePowerRepository private lateinit var testDispatcher: TestDispatcher private lateinit var testScope: TestScope @@ -116,7 +113,6 @@ class UserSwitcherViewModelTest : SysuiTestCase() { } keyguardRepository = FakeKeyguardRepository() - powerRepository = FakePowerRepository() val refreshUsersScheduler = RefreshUsersScheduler( applicationScope = testScope.backgroundScope, @@ -145,7 +141,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() { set(Flags.FACE_AUTH_REFACTOR, true) } underTest = - UserSwitcherViewModel.Factory( + UserSwitcherViewModel( userInteractor = UserInteractor( applicationContext = context, @@ -173,13 +169,8 @@ class UserSwitcherViewModelTest : SysuiTestCase() { refreshUsersScheduler = refreshUsersScheduler, guestUserInteractor = guestUserInteractor, ), - powerInteractor = - PowerInteractor( - repository = powerRepository, - ), guestUserInteractor = guestUserInteractor, ) - .create(UserSwitcherViewModel::class.java) } @Test @@ -326,46 +317,12 @@ class UserSwitcherViewModelTest : SysuiTestCase() { } @Test - fun `isFinishRequested - finishes when user is switched`() = - testScope.runTest { - val userInfos = setUsers(count = 2) - val isFinishRequested = mutableListOf<Boolean>() - val job = - launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) } - assertThat(isFinishRequested.last()).isFalse() - - userRepository.setSelectedUserInfo(userInfos[1]) - - assertThat(isFinishRequested.last()).isTrue() - - job.cancel() - } - - @Test - fun `isFinishRequested - finishes when the screen turns off`() = - testScope.runTest { - setUsers(count = 2) - powerRepository.setInteractive(true) - val isFinishRequested = mutableListOf<Boolean>() - val job = - launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) } - assertThat(isFinishRequested.last()).isFalse() - - powerRepository.setInteractive(false) - - assertThat(isFinishRequested.last()).isTrue() - - job.cancel() - } - - @Test fun `isFinishRequested - finishes when cancel button is clicked`() = testScope.runTest { setUsers(count = 2) - powerRepository.setInteractive(true) val isFinishRequested = mutableListOf<Boolean>() val job = - launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) } + launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) } assertThat(isFinishRequested.last()).isFalse() underTest.onCancelButtonClicked() diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 714be185c972..be719e33dd00 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -38,7 +38,7 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; +import android.compat.annotation.Disabled; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -155,7 +155,7 @@ public class PackageManagerServiceUtils { * allow 3P apps to trigger internal-only functionality. */ @ChangeId - @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + @Disabled /* Revert enforcement: b/274147456 */ private static final long ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS = 161252188; /** |