diff options
91 files changed, 1565 insertions, 1128 deletions
diff --git a/core/java/android/app/search/SearchAction.java b/core/java/android/app/search/SearchAction.java index 9e40e7ebaef0..0c4508a4fb8d 100644 --- a/core/java/android/app/search/SearchAction.java +++ b/core/java/android/app/search/SearchAction.java @@ -67,7 +67,7 @@ public final class SearchAction implements Parcelable { private final UserHandle mUserHandle; @Nullable - private Bundle mExtras; + private final Bundle mExtras; SearchAction(Parcel in) { mId = in.readString(); @@ -99,7 +99,7 @@ public final class SearchAction implements Parcelable { mPendingIntent = pendingIntent; mIntent = intent; mUserHandle = userHandle; - mExtras = extras; + mExtras = extras != null ? extras : new Bundle(); if (mPendingIntent == null && mIntent == null) { throw new IllegalStateException("At least one type of intent should be available."); diff --git a/core/java/android/app/search/SearchTarget.java b/core/java/android/app/search/SearchTarget.java index a590a5d7b767..a3874f7cb007 100644 --- a/core/java/android/app/search/SearchTarget.java +++ b/core/java/android/app/search/SearchTarget.java @@ -185,7 +185,7 @@ public final class SearchTarget implements Parcelable { mShortcutInfo = shortcutInfo; mAppWidgetProviderInfo = appWidgetProviderInfo; mSliceUri = sliceUri; - mExtras = extras; + mExtras = extras != null ? extras : new Bundle(); int published = 0; if (mSearchAction != null) published++; diff --git a/core/java/android/view/WindowLayout.java b/core/java/android/view/WindowLayout.java index 57a0330e3c18..5ed9d2f90a72 100644 --- a/core/java/android/view/WindowLayout.java +++ b/core/java/android/view/WindowLayout.java @@ -118,11 +118,11 @@ public class WindowLayout { } if (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) { if (displayFrame.width() < displayFrame.height()) { - displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE; - displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE; + displayCutoutSafeExceptMaybeBars.top = MIN_Y; + displayCutoutSafeExceptMaybeBars.bottom = MAX_Y; } else { - displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE; - displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE; + displayCutoutSafeExceptMaybeBars.left = MIN_X; + displayCutoutSafeExceptMaybeBars.right = MAX_X; } } final boolean layoutInsetDecor = (attrs.flags & FLAG_LAYOUT_INSET_DECOR) != 0; @@ -132,23 +132,23 @@ public class WindowLayout { final Insets systemBarsInsets = state.calculateInsets( displayFrame, WindowInsets.Type.systemBars(), requestedVisibilities); if (systemBarsInsets.left > 0) { - displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE; + displayCutoutSafeExceptMaybeBars.left = MIN_X; } if (systemBarsInsets.top > 0) { - displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE; + displayCutoutSafeExceptMaybeBars.top = MIN_Y; } if (systemBarsInsets.right > 0) { - displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE; + displayCutoutSafeExceptMaybeBars.right = MAX_X; } if (systemBarsInsets.bottom > 0) { - displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE; + displayCutoutSafeExceptMaybeBars.bottom = MAX_Y; } } if (type == TYPE_INPUT_METHOD) { final InsetsSource navSource = state.peekSource(ITYPE_NAVIGATION_BAR); if (navSource != null && navSource.calculateInsets(displayFrame, true).bottom > 0) { // The IME can always extend under the bottom cutout if the navbar is there. - displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE; + displayCutoutSafeExceptMaybeBars.bottom = MAX_Y; } } final boolean attachedInParent = attachedWindowFrame != null && !layoutInScreen; diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java index 22340c6b0c55..2d669ab58473 100644 --- a/core/java/com/android/internal/jank/InteractionJankMonitor.java +++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java @@ -53,6 +53,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_QS_TILE; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON; +import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_CLEAR_ALL; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_DIALOG_OPEN; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_EXPAND_COLLAPSE_LOCK; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_APPEAR; @@ -210,6 +211,7 @@ public class InteractionJankMonitor { public static final int CUJ_USER_DIALOG_OPEN = 59; public static final int CUJ_TASKBAR_EXPAND = 60; public static final int CUJ_TASKBAR_COLLAPSE = 61; + public static final int CUJ_SHADE_CLEAR_ALL = 62; private static final int NO_STATSD_LOGGING = -1; @@ -280,6 +282,7 @@ public class InteractionJankMonitor { UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_DIALOG_OPEN, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TASKBAR_EXPAND, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TASKBAR_COLLAPSE, + UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_CLEAR_ALL, }; private static volatile InteractionJankMonitor sInstance; @@ -361,7 +364,8 @@ public class InteractionJankMonitor { CUJ_SHADE_DIALOG_OPEN, CUJ_USER_DIALOG_OPEN, CUJ_TASKBAR_EXPAND, - CUJ_TASKBAR_COLLAPSE + CUJ_TASKBAR_COLLAPSE, + CUJ_SHADE_CLEAR_ALL }) @Retention(RetentionPolicy.SOURCE) public @interface CujType { @@ -804,6 +808,8 @@ public class InteractionJankMonitor { return "TASKBAR_EXPAND"; case CUJ_TASKBAR_COLLAPSE: return "TASKBAR_COLLAPSE"; + case CUJ_SHADE_CLEAR_ALL: + return "SHADE_CLEAR_ALL"; } return "UNKNOWN"; } diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt index 4b0c62bff60d..cc7d23e97d0c 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt @@ -106,7 +106,7 @@ class ViewHierarchyAnimator { ephemeral: Boolean ): Boolean { if ( - !isVisible( + !occupiesSpace( rootView.visibility, rootView.left, rootView.top, @@ -177,7 +177,7 @@ class ViewHierarchyAnimator { fadeInInterpolator: Interpolator = DEFAULT_FADE_IN_INTERPOLATOR ): Boolean { if ( - isVisible( + occupiesSpace( rootView.visibility, rootView.left, rootView.top, @@ -295,7 +295,7 @@ class ViewHierarchyAnimator { (view.getTag(R.id.tag_animator) as? ObjectAnimator)?.cancel() - if (!isVisible(view.visibility, left, top, right, bottom)) { + if (!occupiesSpace(view.visibility, left, top, right, bottom)) { setBound(view, Bound.LEFT, left) setBound(view, Bound.TOP, top) setBound(view, Bound.RIGHT, right) @@ -362,7 +362,7 @@ class ViewHierarchyAnimator { duration: Long = DEFAULT_DURATION ): Boolean { if ( - !isVisible( + !occupiesSpace( rootView.visibility, rootView.left, rootView.top, @@ -530,17 +530,17 @@ class ViewHierarchyAnimator { } /** - * Returns whether the given [visibility] and bounds are consistent with a view being - * currently visible on screen. + * Returns whether the given [visibility] and bounds are consistent with a view being a + * contributing part of the hierarchy. */ - private fun isVisible( + private fun occupiesSpace( visibility: Int, left: Int, top: Int, right: Int, bottom: Int ): Boolean { - return visibility == View.VISIBLE && left != right && top != bottom + return visibility != View.GONE && left != right && top != bottom } /** diff --git a/packages/SystemUI/docs/user-file-manager.md b/packages/SystemUI/docs/user-file-manager.md new file mode 100644 index 000000000000..64f1694af50a --- /dev/null +++ b/packages/SystemUI/docs/user-file-manager.md @@ -0,0 +1,13 @@ +# UserFileManager + +This class is used to generate file paths and SharedPreferences that is compatible for multiple +users in SystemUI. Due to constraints in SystemUI, we can only read/write files as the system user. +Therefore, for secondary users, we want to store secondary user specific files into the system user +directory. + +## Handling User Removal + +This class will listen for Intent.ACTION_USER_REMOVED and remove directories that no longer +corresponding to active users. Additionally, upon start up, the class will run the same query for +deletion to ensure that there is no stale data. + diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index ef672f3a6213..176e5818f5bd 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -802,6 +802,8 @@ <!-- Message shown when lock screen is unlocked (ie: by trust agent) and the user taps the empty space on the lock screen and UDFPS is supported. Provides extra instructions for how the user can enter their device [CHAR LIMIT=60] --> <string name="keyguard_unlock_press">Press the unlock icon to open</string> + <!-- Message shown when non-bypass face authentication succeeds. Provides extra instructions for how the user can enter their device [CHAR LIMIT=60] --> + <string name="keyguard_face_successful_unlock_swipe">Unlocked by face. Swipe up to open.</string> <!-- Message shown when non-bypass face authentication succeeds and UDFPS is supported. Provides extra instructions for how the user can enter their device [CHAR LIMIT=60] --> <string name="keyguard_face_successful_unlock_press">Unlocked by face. Press the unlock icon to open.</string> <!-- Message shown when non-bypass face authentication succeeds and UDFPS is supported. Provides extra instructions for how the user can enter their device [CHAR LIMIT=60] --> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java index 12fa401d7fea..d32219a9817f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java @@ -336,6 +336,11 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView> mKeyguardSecurityContainerController.onStartingToHide(); } + /** Called when bouncer visibility changes. */ + public void onBouncerVisibilityChanged(@View.Visibility int visibility) { + mKeyguardSecurityContainerController.onBouncerVisibilityChanged(visibility); + } + public boolean hasDismissActions() { return mDismissAction != null || mCancelAction != null; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 61e262440607..5ee659be6dd2 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -17,6 +17,7 @@ package com.android.keyguard; import static android.app.StatusBarManager.SESSION_KEYGUARD; +import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT; import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC; import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_EXTENDED_ACCESS; @@ -32,11 +33,13 @@ import android.app.admin.DevicePolicyManager; import android.content.Intent; import android.content.res.ColorStateList; import android.content.res.Configuration; +import android.hardware.biometrics.BiometricSourceType; import android.metrics.LogMaker; import android.os.UserHandle; import android.util.Log; import android.util.Slog; import android.view.MotionEvent; +import android.view.View; import androidx.annotation.Nullable; @@ -55,6 +58,7 @@ import com.android.keyguard.dagger.KeyguardBouncerScope; import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.Gefingerpoken; import com.android.systemui.R; +import com.android.systemui.biometrics.SidefpsController; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; @@ -67,6 +71,8 @@ import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.ViewController; import com.android.systemui.util.settings.GlobalSettings; +import java.util.Optional; + import javax.inject.Inject; /** Controller for {@link KeyguardSecurityContainer} */ @@ -93,6 +99,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final GlobalSettings mGlobalSettings; private final FeatureFlags mFeatureFlags; private final SessionTracker mSessionTracker; + private final Optional<SidefpsController> mSidefpsController; private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED; @@ -236,13 +243,27 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard reloadColors(); } }; + private boolean mBouncerVisible = false; private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { - @Override - public void onDevicePolicyManagerStateChanged() { - showPrimarySecurityScreen(false); - } - }; + @Override + public void onDevicePolicyManagerStateChanged() { + showPrimarySecurityScreen(false); + } + + @Override + public void onBiometricRunningStateChanged(boolean running, + BiometricSourceType biometricSourceType) { + if (biometricSourceType == FINGERPRINT) { + updateSideFpsVisibility(); + } + } + + @Override + public void onStrongAuthStateChanged(int userId) { + updateSideFpsVisibility(); + } + }; private KeyguardSecurityContainerController(KeyguardSecurityContainer view, AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory, @@ -260,7 +281,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard UserSwitcherController userSwitcherController, FeatureFlags featureFlags, GlobalSettings globalSettings, - SessionTracker sessionTracker) { + SessionTracker sessionTracker, + Optional<SidefpsController> sidefpsController) { super(view); mLockPatternUtils = lockPatternUtils; mUpdateMonitor = keyguardUpdateMonitor; @@ -280,6 +302,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mFeatureFlags = featureFlags; mGlobalSettings = globalSettings; mSessionTracker = sessionTracker; + mSidefpsController = sidefpsController; } @Override @@ -311,8 +334,23 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard getCurrentSecurityController().onPause(); } mView.onPause(); + // It might happen that onStartingToHide is not called when the device is locked while on + // bouncer. + setBouncerVisible(false); } + private void updateSideFpsVisibility() { + if (!mSidefpsController.isPresent()) { + return; + } + if (mBouncerVisible && mView.isSidedSecurityMode() + && mUpdateMonitor.isFingerprintDetectionRunning() + && !mUpdateMonitor.userNeedsStrongAuth()) { + mSidefpsController.get().show(); + } else { + mSidefpsController.get().hide(); + } + } /** * Shows the primary security screen for the user. This will be either the multi-selector @@ -397,6 +435,17 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard if (mCurrentSecurityMode != SecurityMode.None) { getCurrentSecurityController().onStartingToHide(); } + setBouncerVisible(false); + } + + /** Called when the bouncer changes visibility. */ + public void onBouncerVisibilityChanged(@View.Visibility int visibility) { + setBouncerVisible(visibility == View.VISIBLE); + } + + private void setBouncerVisible(boolean visible) { + mBouncerVisible = visible; + updateSideFpsVisibility(); } /** @@ -655,6 +704,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final FeatureFlags mFeatureFlags; private final UserSwitcherController mUserSwitcherController; private final SessionTracker mSessionTracker; + private final Optional<SidefpsController> mSidefpsController; @Inject Factory(KeyguardSecurityContainer view, @@ -673,7 +723,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard UserSwitcherController userSwitcherController, FeatureFlags featureFlags, GlobalSettings globalSettings, - SessionTracker sessionTracker) { + SessionTracker sessionTracker, + Optional<SidefpsController> sidefpsController) { mView = view; mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory; mLockPatternUtils = lockPatternUtils; @@ -690,6 +741,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mGlobalSettings = globalSettings; mUserSwitcherController = userSwitcherController; mSessionTracker = sessionTracker; + mSidefpsController = sidefpsController; } public KeyguardSecurityContainerController create( @@ -699,7 +751,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger, mKeyguardStateController, securityCallback, mSecurityViewFlipperController, mConfigurationController, mFalsingCollector, mFalsingManager, - mUserSwitcherController, mFeatureFlags, mGlobalSettings, mSessionTracker); + mUserSwitcherController, mFeatureFlags, mGlobalSettings, mSessionTracker, + mSidefpsController); } } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index ede62437e5a0..cdb3abf80c57 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -2052,17 +2052,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab .getServiceStateForSubscriber(subId); mHandler.sendMessage( mHandler.obtainMessage(MSG_SERVICE_STATE_CHANGE, subId, 0, serviceState)); - - // Get initial state. Relying on Sticky behavior until API for getting info. - if (mBatteryStatus == null) { - Intent intent = mContext.registerReceiver( - null, - new IntentFilter(Intent.ACTION_BATTERY_CHANGED) - ); - if (intent != null && mBatteryStatus == null) { - mBroadcastReceiver.onReceive(mContext, intent); - } - } }); final IntentFilter allUserFilter = new IntentFilter(); diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java index b3c11584bcf8..49e97836b18b 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java @@ -16,6 +16,10 @@ package com.android.keyguard.dagger; +import static com.android.systemui.biometrics.SidefpsControllerKt.hasSideFpsSensor; + +import android.annotation.Nullable; +import android.hardware.fingerprint.FingerprintManager; import android.view.LayoutInflater; import android.view.ViewGroup; @@ -23,9 +27,14 @@ import com.android.keyguard.KeyguardHostView; import com.android.keyguard.KeyguardSecurityContainer; import com.android.keyguard.KeyguardSecurityViewFlipper; import com.android.systemui.R; +import com.android.systemui.biometrics.SidefpsController; import com.android.systemui.dagger.qualifiers.RootView; import com.android.systemui.statusbar.phone.KeyguardBouncer; +import java.util.Optional; + +import javax.inject.Provider; + import dagger.Module; import dagger.Provides; @@ -60,4 +69,16 @@ public interface KeyguardBouncerModule { KeyguardSecurityContainer containerView) { return containerView.findViewById(R.id.view_flipper); } + + /** Provides {@link SidefpsController} if the device has the side fingerprint sensor. */ + @Provides + @KeyguardBouncerScope + static Optional<SidefpsController> providesOptionalSidefpsController( + @Nullable FingerprintManager fingerprintManager, + Provider<SidefpsController> sidefpsControllerProvider) { + if (!hasSideFpsSensor(fingerprintManager)) { + return Optional.empty(); + } + return Optional.of(sidefpsControllerProvider.get()); + } } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index b05582ee1ec9..ca94b8cd05b7 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -16,7 +16,6 @@ package com.android.systemui; -import android.app.ActivityThread; import android.content.Context; import android.content.res.Resources; import android.os.Handler; @@ -28,14 +27,13 @@ import com.android.systemui.dagger.DaggerGlobalRootComponent; import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dagger.SysUIComponent; import com.android.systemui.dagger.WMComponent; -import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider; +import com.android.systemui.util.InitializationChecker; import com.android.wm.shell.dagger.WMShellConcurrencyModule; import com.android.wm.shell.transition.ShellTransitions; import java.util.Map; import java.util.Optional; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; import javax.inject.Provider; @@ -49,7 +47,7 @@ public class SystemUIFactory { private GlobalRootComponent mRootComponent; private WMComponent mWMComponent; private SysUIComponent mSysUIComponent; - private boolean mInitializeComponents; + private InitializationChecker mInitializationChecker; public static <T extends SystemUIFactory> T getInstance() { return (T) mFactory; @@ -91,15 +89,17 @@ public class SystemUIFactory { @VisibleForTesting public void init(Context context, boolean fromTest) throws ExecutionException, InterruptedException { - // Only initialize components for the main system ui process running as the primary user - mInitializeComponents = !fromTest - && android.os.Process.myUserHandle().isSystem() - && ActivityThread.currentProcessName().equals(ActivityThread.currentPackageName()); - mRootComponent = buildGlobalRootComponent(context); + mRootComponent = getGlobalRootComponentBuilder() + .context(context) + .instrumentationTest(fromTest) + .build(); + + mInitializationChecker = mRootComponent.getInitializationChecker(); + boolean initializeComponents = mInitializationChecker.initializeComponents(); // Stand up WMComponent setupWmComponent(context); - if (mInitializeComponents) { + if (initializeComponents) { // Only initialize when not starting from tests since this currently initializes some // components that shouldn't be run in the test environment mWMComponent.init(); @@ -107,7 +107,7 @@ public class SystemUIFactory { // And finally, retrieve whatever SysUI needs from WMShell and build SysUI. SysUIComponent.Builder builder = mRootComponent.getSysUIComponent(); - if (mInitializeComponents) { + if (initializeComponents) { // Only initialize when not starting from tests since this currently initializes some // components that shouldn't be run in the test environment builder = prepareSysUIComponentBuilder(builder, mWMComponent) @@ -147,7 +147,7 @@ public class SystemUIFactory { .setBackAnimation(Optional.ofNullable(null)); } mSysUIComponent = builder.build(); - if (mInitializeComponents) { + if (initializeComponents) { mSysUIComponent.init(); } @@ -165,7 +165,8 @@ public class SystemUIFactory { */ private void setupWmComponent(Context context) { WMComponent.Builder wmBuilder = mRootComponent.getWMComponentBuilder(); - if (!mInitializeComponents || !WMShellConcurrencyModule.enableShellMainThread(context)) { + if (!mInitializationChecker.initializeComponents() + || !WMShellConcurrencyModule.enableShellMainThread(context)) { // If running under tests or shell thread is not enabled, we don't need anything special mWMComponent = wmBuilder.build(); return; @@ -197,14 +198,8 @@ public class SystemUIFactory { return sysUIBuilder; } - protected GlobalRootComponent buildGlobalRootComponent(Context context) { - return DaggerGlobalRootComponent.builder() - .context(context) - .build(); - } - - protected boolean shouldInitializeComponents() { - return mInitializeComponents; + protected GlobalRootComponent.Builder getGlobalRootComponentBuilder() { + return DaggerGlobalRootComponent.builder(); } public GlobalRootComponent getRootComponent() { @@ -239,14 +234,4 @@ public class SystemUIFactory { public Map<Class<?>, Provider<CoreStartable>> getStartableComponentsPerUser() { return mSysUIComponent.getPerUserStartables(); } - - /** - * Creates an instance of ScreenshotNotificationSmartActionsProvider. - * This method is overridden in vendor specific implementation of Sys UI. - */ - public ScreenshotNotificationSmartActionsProvider - createScreenshotNotificationSmartActionsProvider( - Context context, Executor executor, Handler uiHandler) { - return new ScreenshotNotificationSmartActionsProvider(); - } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt index 04e2dccda528..bbffb73b7503 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt @@ -34,16 +34,16 @@ import android.hardware.fingerprint.ISidefpsController import android.os.Handler import android.util.Log import android.util.RotationUtils -import android.view.View.AccessibilityDelegate -import android.view.accessibility.AccessibilityEvent import android.view.Display import android.view.Gravity import android.view.LayoutInflater import android.view.Surface import android.view.View +import android.view.View.AccessibilityDelegate import android.view.ViewPropertyAnimator import android.view.WindowInsets import android.view.WindowManager +import android.view.accessibility.AccessibilityEvent import androidx.annotation.RawRes import com.airbnb.lottie.LottieAnimationView import com.airbnb.lottie.LottieProperty @@ -70,13 +70,12 @@ class SidefpsController @Inject constructor( private val activityTaskManager: ActivityTaskManager, overviewProxyService: OverviewProxyService, displayManager: DisplayManager, - @Main mainExecutor: DelayableExecutor, + @Main private val mainExecutor: DelayableExecutor, @Main private val handler: Handler ) { @VisibleForTesting val sensorProps: FingerprintSensorPropertiesInternal = fingerprintManager - ?.sensorPropertiesInternal - ?.firstOrNull { it.isAnySidefpsType } + ?.sideFpsSensorProperties ?: throw IllegalStateException("no side fingerprint sensor") @VisibleForTesting @@ -135,25 +134,34 @@ class SidefpsController @Inject constructor( } init { - fingerprintManager?.setSidefpsController(object : ISidefpsController.Stub() { - override fun show( - sensorId: Int, - @BiometricOverlayConstants.ShowReason reason: Int - ) = if (reason.isReasonToShow(activityTaskManager)) doShow() else hide(sensorId) - - private fun doShow() = mainExecutor.execute { - if (overlayView == null) { - createOverlayForDisplay() - } else { - Log.v(TAG, "overlay already shown") - } - } + fingerprintManager?.setSidefpsController( + object : ISidefpsController.Stub() { + override fun show( + sensorId: Int, + @BiometricOverlayConstants.ShowReason reason: Int + ) = if (reason.isReasonToShow(activityTaskManager)) show() else hide() - override fun hide(sensorId: Int) = mainExecutor.execute { overlayView = null } - }) + override fun hide(sensorId: Int) = hide() + }) overviewProxyService.addCallback(overviewProxyListener) } + /** Shows the side fps overlay if not already shown. */ + fun show() { + mainExecutor.execute { + if (overlayView == null) { + createOverlayForDisplay() + } else { + Log.v(TAG, "overlay already shown") + } + } + } + + /** Hides the fps overlay if shown. */ + fun hide() { + mainExecutor.execute { overlayView = null } + } + private fun onOrientationChanged() { if (overlayView != null) { createOverlayForDisplay() @@ -266,6 +274,12 @@ class SidefpsController @Inject constructor( } } +private val FingerprintManager?.sideFpsSensorProperties: FingerprintSensorPropertiesInternal? + get() = this?.sensorPropertiesInternal?.firstOrNull { it.isAnySidefpsType } + +/** Returns [True] when the device has a side fingerprint sensor. */ +fun FingerprintManager?.hasSideFpsSensor(): Boolean = this?.sideFpsSensorProperties != null + @BiometricOverlayConstants.ShowReason private fun Int.isReasonToShow(activityTaskManager: ActivityTaskManager): Boolean = when (this) { REASON_AUTH_KEYGUARD -> false diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java index 4f55ba496b6b..9e33ee1faab3 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java @@ -18,6 +18,9 @@ package com.android.systemui.dagger; import android.content.Context; +import com.android.systemui.dagger.qualifiers.InstrumentationTest; +import com.android.systemui.util.InitializationChecker; + import javax.inject.Singleton; import dagger.BindsInstance; @@ -37,7 +40,8 @@ public interface GlobalRootComponent { interface Builder { @BindsInstance Builder context(Context context); - + @BindsInstance + Builder instrumentationTest(@InstrumentationTest boolean test); GlobalRootComponent build(); } @@ -50,4 +54,9 @@ public interface GlobalRootComponent { * Builder for a {@link SysUIComponent}, which makes it a subcomponent of this class. */ SysUIComponent.Builder getSysUIComponent(); + + /** + * Returns an {@link InitializationChecker}. + */ + InitializationChecker getInitializationChecker(); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java index c4fca60d4b44..2c1463d285f6 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java @@ -44,6 +44,7 @@ import com.android.systemui.qs.dagger.QSModule; import com.android.systemui.qs.tileimpl.QSFactoryImpl; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsImplementation; +import com.android.systemui.screenshot.ReferenceScreenshotModule; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; @@ -99,6 +100,7 @@ import dagger.Provides; MediaModule.class, PowerModule.class, QSModule.class, + ReferenceScreenshotModule.class, StartCentralSurfacesModule.class, VolumeModule.class }) diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt index a9f340854689..6db3e82a77b0 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt @@ -33,6 +33,7 @@ import com.android.systemui.log.SessionTracker import com.android.systemui.media.RingtonePlayer import com.android.systemui.power.PowerUI import com.android.systemui.recents.Recents +import com.android.systemui.settings.dagger.MultiUserUtilsModule import com.android.systemui.shortcut.ShortcutKeyDispatcher import com.android.systemui.statusbar.notification.InstantAppNotifier import com.android.systemui.statusbar.phone.KeyguardLiftController @@ -51,7 +52,7 @@ import dagger.multibindings.IntoMap /** * Collection of {@link CoreStartable}s that should be run on AOSP. */ -@Module +@Module(includes = [MultiUserUtilsModule::class]) abstract class SystemUICoreStartableModule { /** Inject into AuthController. */ @Binds @@ -205,4 +206,4 @@ abstract class SystemUICoreStartableModule { @IntoMap @ClassKey(KeyguardLiftController::class) abstract fun bindKeyguardLiftController(sysui: KeyguardLiftController): CoreStartable -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 137e28888728..c8747fcf16fb 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -50,7 +50,7 @@ import com.android.systemui.plugins.BcSmartspaceDataPlugin; import com.android.systemui.privacy.PrivacyModule; import com.android.systemui.recents.Recents; import com.android.systemui.screenshot.dagger.ScreenshotModule; -import com.android.systemui.settings.dagger.SettingsModule; +import com.android.systemui.settings.dagger.MultiUserUtilsModule; import com.android.systemui.smartspace.dagger.SmartspaceModule; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; @@ -127,7 +127,7 @@ import dagger.Provides; QsFrameTranslateModule.class, ScreenshotModule.class, SensorModule.class, - SettingsModule.class, + MultiUserUtilsModule.class, SettingsUtilModule.class, SmartRepliesInflationModule.class, SmartspaceModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/InstrumentationTest.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/InstrumentationTest.java new file mode 100644 index 000000000000..a803a39f114f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/InstrumentationTest.java @@ -0,0 +1,34 @@ +/* + * 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.dagger.qualifiers; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Qualifier; + + +/** + * An annotation for injecting whether or not we are running in a test environment. + */ +@Qualifier +@Documented +@Retention(RUNTIME) +public @interface InstrumentationTest { +} diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java index d0ac1c059eb1..245ea219ea68 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -199,7 +199,8 @@ public class Flags { public static final SysPropBooleanFlag WM_ALWAYS_ENFORCE_PREDICTIVE_BACK = new SysPropBooleanFlag(1202, "persist.wm.debug.predictive_back_always_enforce", false); - public static final BooleanFlag NEW_BACK_AFFORDANCE = new BooleanFlag(1203, true); + public static final BooleanFlag NEW_BACK_AFFORDANCE = + new BooleanFlag(1203, false /* default */, true /* teamfood */); // Pay no attention to the reflection behind the curtain. // ========================== Curtain ========================== diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt index a83367059736..28ab83c83a42 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt @@ -30,6 +30,7 @@ import android.view.Gravity import android.view.MotionEvent import android.view.VelocityTracker import android.view.View +import android.view.ViewConfiguration import android.view.WindowManager import android.view.animation.DecelerateInterpolator import android.view.animation.PathInterpolator @@ -98,6 +99,7 @@ class BackPanelController private constructor( context: Context, private var backAnimation: BackAnimation?, private val windowManager: WindowManager, + private val viewConfiguration: ViewConfiguration, @Main private val mainHandler: Handler, private val vibratorHelper: VibratorHelper, private val configurationController: ConfigurationController, @@ -112,6 +114,7 @@ class BackPanelController private constructor( */ class Factory @Inject constructor( private val windowManager: WindowManager, + private val viewConfiguration: ViewConfiguration, @Main private val mainHandler: Handler, private val vibratorHelper: VibratorHelper, private val configurationController: ConfigurationController, @@ -123,6 +126,7 @@ class BackPanelController private constructor( context, backAnimation, windowManager, + viewConfiguration, mainHandler, vibratorHelper, configurationController, @@ -164,6 +168,10 @@ class BackPanelController private constructor( private var gestureStartTime = 0L + // Whether the current gesture has moved a sufficiently large amount, + // so that we can unambiguously start showing the ENTRY animation + private var hasPassedDragSlop = false + private val failsafeRunnable = Runnable { onFailsafe() } private enum class GestureState { @@ -304,18 +312,17 @@ class BackPanelController private constructor( startX = event.x startY = event.y gestureStartTime = SystemClock.uptimeMillis() - - // Reset the arrow to the side - updateArrowState(GestureState.ENTRY) - - windowManager.updateViewLayout(mView, layoutParams) - mView.startTrackingShowBackArrowLatency() } - MotionEvent.ACTION_MOVE -> handleMoveEvent(event) + MotionEvent.ACTION_MOVE -> { + // only go to the ENTRY state after some minimum motion has occurred + if (dragSlopExceeded(event.x, startX)) { + handleMoveEvent(event) + } + } MotionEvent.ACTION_UP -> { if (currentState == GestureState.ACTIVE) { updateArrowState(if (isFlung()) GestureState.FLUNG else GestureState.COMMITTED) - } else { + } else if (currentState != GestureState.GONE) { // if invisible, skip animation updateArrowState(GestureState.CANCELLED) } velocityTracker = null @@ -330,6 +337,28 @@ class BackPanelController private constructor( } } + /** + * Returns false until the current gesture exceeds the touch slop threshold, + * and returns true thereafter (we reset on the subsequent back gesture). + * The moment it switches from false -> true is important, + * because that's when we switch state, from GONE -> ENTRY. + * @return whether the current gesture has moved past a minimum threshold. + */ + private fun dragSlopExceeded(curX: Float, startX: Float): Boolean { + if (hasPassedDragSlop) return true + + if (abs(curX - startX) > viewConfiguration.scaledTouchSlop) { + // Reset the arrow to the side + updateArrowState(GestureState.ENTRY) + + windowManager.updateViewLayout(mView, layoutParams) + mView.startTrackingShowBackArrowLatency() + + hasPassedDragSlop = true + } + return hasPassedDragSlop + } + private fun updateArrowStateOnMove(yTranslation: Float, xTranslation: Float) { if (!currentState.isInteractive()) return @@ -533,6 +562,7 @@ class BackPanelController private constructor( } private fun resetOnDown() { + hasPassedDragSlop = false hasHapticPlayed = false totalTouchDelta = 0f vibrationTime = 0 diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index bd6a5fc8661b..067f4cbb975e 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -53,7 +53,6 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.ViewConfiguration; import android.view.WindowManager; -import android.view.WindowMetrics; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.policy.GestureNavigationSettingsObserver; @@ -133,7 +132,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker @Override public void onPrioritizedRotation(@Surface.Rotation int rotation) { mStartingQuickstepRotation = rotation; - updateDisabledForQuickstep(mContext.getResources().getConfiguration()); + updateDisabledForQuickstep(mLastReportedConfig); } }; @@ -183,6 +182,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker private final IWindowManager mWindowManagerService; private final Optional<Pip> mPipOptional; private final FalsingManager mFalsingManager; + private final Configuration mLastReportedConfig = new Configuration(); // Activities which should not trigger Back gesture. private final List<ComponentName> mGestureBlockingActivities = new ArrayList<>(); @@ -338,6 +338,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker mLatencyTracker = latencyTracker; mBackGestureTfClassifierProviderProvider = backGestureTfClassifierProviderProvider; mFeatureFlags = featureFlags; + mLastReportedConfig.setTo(mContext.getResources().getConfiguration()); ComponentName recentsComponentName = ComponentName.unflattenFromString( context.getString(com.android.internal.R.string.config_recentsComponentName)); if (recentsComponentName != null) { @@ -886,12 +887,12 @@ public class EdgeBackGestureHandler extends CurrentUserTracker if (DEBUG_MISSING_GESTURE) { Log.d(DEBUG_MISSING_GESTURE_TAG, "Config changed: config=" + newConfig); } + mLastReportedConfig.updateFrom(newConfig); updateDisplaySize(); } private void updateDisplaySize() { - WindowMetrics metrics = mWindowManager.getMaximumWindowMetrics(); - Rect bounds = metrics.getBounds(); + Rect bounds = mLastReportedConfig.windowConfiguration.getMaxBounds(); mDisplaySize.set(bounds.width(), bounds.height()); if (DEBUG_MISSING_GESTURE) { Log.d(DEBUG_MISSING_GESTURE_TAG, "Update display size: mDisplaySize=" + mDisplaySize); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java index daaa897374cb..814b8e90e0dd 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java @@ -102,7 +102,7 @@ public class ActionProxyReceiver extends BroadcastReceiver { ? ACTION_TYPE_EDIT : ACTION_TYPE_SHARE; mScreenshotSmartActions.notifyScreenshotAction( - context, intent.getStringExtra(EXTRA_ID), actionType, false, null); + intent.getStringExtra(EXTRA_ID), actionType, false, null); } } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java index 8d44205bef30..e0346f2e2a98 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java @@ -62,7 +62,7 @@ public class DeleteScreenshotReceiver extends BroadcastReceiver { }); if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) { mScreenshotSmartActions.notifyScreenshotAction( - context, intent.getStringExtra(EXTRA_ID), ACTION_TYPE_DELETE, false, null); + intent.getStringExtra(EXTRA_ID), ACTION_TYPE_DELETE, false, null); } } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ReferenceScreenshotModule.java b/packages/SystemUI/src/com/android/systemui/screenshot/ReferenceScreenshotModule.java new file mode 100644 index 000000000000..6224e1bf2414 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ReferenceScreenshotModule.java @@ -0,0 +1,32 @@ +/* + * 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.screenshot; + +import dagger.Module; +import dagger.Provides; + +/** + * + */ +@Module +public interface ReferenceScreenshotModule { + /** */ + @Provides + static ScreenshotNotificationSmartActionsProvider providesScrnshtNotifSmartActionsProvider() { + return new ScreenshotNotificationSmartActionsProvider(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java index 50ee1f7ba97a..f248d6913878 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java @@ -38,7 +38,6 @@ import android.graphics.drawable.Icon; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; -import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -49,7 +48,6 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.systemui.R; -import com.android.systemui.SystemUIFactory; import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition; import com.google.common.util.concurrent.ListenableFuture; @@ -89,7 +87,10 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { SaveImageInBackgroundTask(Context context, ImageExporter exporter, ScreenshotSmartActions screenshotSmartActions, ScreenshotController.SaveImageInBackgroundData data, - Supplier<ActionTransition> sharedElementTransition) { + Supplier<ActionTransition> sharedElementTransition, + ScreenshotNotificationSmartActionsProvider + screenshotNotificationSmartActionsProvider + ) { mContext = context; mScreenshotSmartActions = screenshotSmartActions; mImageData = new ScreenshotController.SavedImageData(); @@ -103,15 +104,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { // Initialize screenshot notification smart actions provider. mSmartActionsEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, true); - if (mSmartActionsEnabled) { - mSmartActionsProvider = - SystemUIFactory.getInstance() - .createScreenshotNotificationSmartActionsProvider( - context, THREAD_POOL_EXECUTOR, new Handler()); - } else { - // If smart actions is not enabled use empty implementation. - mSmartActionsProvider = new ScreenshotNotificationSmartActionsProvider(); - } + mSmartActionsProvider = screenshotNotificationSmartActionsProvider; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index c213f192291a..89a15f65e98f 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -263,6 +263,8 @@ public class ScreenshotController { private final ScrollCaptureController mScrollCaptureController; private final LongScreenshotData mLongScreenshotHolder; private final boolean mIsLowRamDevice; + private final ScreenshotNotificationSmartActionsProvider + mScreenshotNotificationSmartActionsProvider; private final TimeoutHandler mScreenshotHandler; private ScreenshotView mScreenshotView; @@ -298,7 +300,9 @@ public class ScreenshotController { LongScreenshotData longScreenshotHolder, ActivityManager activityManager, TimeoutHandler timeoutHandler, - BroadcastSender broadcastSender) { + BroadcastSender broadcastSender, + ScreenshotNotificationSmartActionsProvider screenshotNotificationSmartActionsProvider + ) { mScreenshotSmartActions = screenshotSmartActions; mNotificationsController = screenshotNotificationsController; mScrollCaptureClient = scrollCaptureClient; @@ -308,6 +312,7 @@ public class ScreenshotController { mScrollCaptureController = scrollCaptureController; mLongScreenshotHolder = longScreenshotHolder; mIsLowRamDevice = activityManager.isLowRamDevice(); + mScreenshotNotificationSmartActionsProvider = screenshotNotificationSmartActionsProvider; mBgExecutor = Executors.newSingleThreadExecutor(); mBroadcastSender = broadcastSender; @@ -956,7 +961,8 @@ public class ScreenshotController { } mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mImageExporter, - mScreenshotSmartActions, data, getActionTransitionSupplier()); + mScreenshotSmartActions, data, getActionTransitionSupplier(), + mScreenshotNotificationSmartActionsProvider); mSaveInBgTask.execute(); } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java index 0527818135dd..68b46d2b7525 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java @@ -16,8 +16,6 @@ package com.android.systemui.screenshot; -import static android.os.AsyncTask.THREAD_POOL_EXECUTOR; - import static com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS; import static com.android.systemui.screenshot.LogConfig.logTag; import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType; @@ -25,17 +23,14 @@ import static com.android.systemui.screenshot.ScreenshotNotificationSmartActions import android.app.ActivityManager; import android.app.Notification; import android.content.ComponentName; -import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; -import android.os.Handler; import android.os.SystemClock; import android.os.UserHandle; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.SystemUIFactory; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -46,6 +41,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import javax.inject.Inject; +import javax.inject.Provider; /** * Collects the static functions for retrieving and acting on smart actions. @@ -53,9 +49,17 @@ import javax.inject.Inject; @SysUISingleton public class ScreenshotSmartActions { private static final String TAG = logTag(ScreenshotSmartActions.class); + private final Provider<ScreenshotNotificationSmartActionsProvider> + mScreenshotNotificationSmartActionsProviderProvider; @Inject - public ScreenshotSmartActions() {} + public ScreenshotSmartActions( + Provider<ScreenshotNotificationSmartActionsProvider> + screenshotNotificationSmartActionsProviderProvider + ) { + mScreenshotNotificationSmartActionsProviderProvider = + screenshotNotificationSmartActionsProviderProvider; + } @VisibleForTesting CompletableFuture<List<Notification.Action>> getSmartActionsFuture( @@ -165,12 +169,11 @@ public class ScreenshotSmartActions { } } - void notifyScreenshotAction(Context context, String screenshotId, String action, + void notifyScreenshotAction(String screenshotId, String action, boolean isSmartAction, Intent intent) { try { ScreenshotNotificationSmartActionsProvider provider = - SystemUIFactory.getInstance().createScreenshotNotificationSmartActionsProvider( - context, THREAD_POOL_EXECUTOR, new Handler()); + mScreenshotNotificationSmartActionsProviderProvider.get(); if (DEBUG_ACTIONS) { Log.d(TAG, String.format("%s notifyAction: %s id=%s, isSmartAction=%b", provider.getClass(), action, screenshotId, isSmartAction)); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java index f703058f4a0f..45af1874e9db 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java @@ -60,7 +60,7 @@ public class SmartActionsReceiver extends BroadcastReceiver { } mScreenshotSmartActions.notifyScreenshotAction( - context, intent.getStringExtra(EXTRA_ID), actionType, true, + intent.getStringExtra(EXTRA_ID), actionType, true, pendingIntent.getIntent()); } } diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserFileManager.kt b/packages/SystemUI/src/com/android/systemui/settings/UserFileManager.kt new file mode 100644 index 000000000000..aa218dbfdd43 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/settings/UserFileManager.kt @@ -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.systemui.settings + +import android.content.Context +import android.content.SharedPreferences +import java.io.File + +/** + * Interface for retrieving file paths for file storage of system and secondary users. + */ +interface UserFileManager { + /** + * Return the file based on current user. + */ + fun getFile(fileName: String, userId: Int): File + /** + * Get shared preferences from user. + */ + fun getSharedPreferences( + fileName: String, + @Context.PreferencesMode mode: Int, + userId: Int + ): SharedPreferences +} diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt new file mode 100644 index 000000000000..8c8f54fe9c3d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt @@ -0,0 +1,144 @@ +/* + * 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.settings + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.content.SharedPreferences +import android.os.Environment +import android.os.UserHandle +import android.os.UserManager +import android.util.Log +import androidx.annotation.VisibleForTesting +import com.android.systemui.CoreStartable +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.util.concurrency.DelayableExecutor +import java.io.File +import javax.inject.Inject + +/** + * Implementation for retrieving file paths for file storage of system and secondary users. + * Files lie in {File Directory}/UserFileManager/{User Id} for secondary user. + * For system user, we use the conventional {File Directory} + */ +@SysUISingleton +class UserFileManagerImpl @Inject constructor( + // Context of system process and system user. + val context: Context, + val userManager: UserManager, + val broadcastDispatcher: BroadcastDispatcher, + @Background val backgroundExecutor: DelayableExecutor +) : UserFileManager, CoreStartable(context) { + companion object { + private const val FILES = "files" + private const val SHARED_PREFS = "shared_prefs" + internal const val ID = "UserFileManager" + } + + private val broadcastReceiver = object : BroadcastReceiver() { + /** + * Listen to Intent.ACTION_USER_REMOVED to clear user data. + */ + override fun onReceive(context: Context, intent: Intent) { + if (intent.action == Intent.ACTION_USER_REMOVED) { + clearDeletedUserData() + } + } + } + + /** + * Poll for user-specific directories to delete upon start up. + */ + override fun start() { + clearDeletedUserData() + val filter = IntentFilter().apply { + addAction(Intent.ACTION_USER_REMOVED) + } + broadcastDispatcher.registerReceiver(broadcastReceiver, filter, backgroundExecutor) + } + + /** + * Return the file based on current user. + */ + override fun getFile(fileName: String, userId: Int): File { + return if (UserHandle(userId).isSystem) { + Environment.buildPath( + context.filesDir, + fileName + ) + } else { + Environment.buildPath( + context.filesDir, + ID, + userId.toString(), + FILES, + fileName + ) + } + } + + /** + * Get shared preferences from user. + */ + override fun getSharedPreferences( + fileName: String, + @Context.PreferencesMode mode: Int, + userId: Int + ): SharedPreferences { + if (UserHandle(userId).isSystem) { + return context.getSharedPreferences(fileName, mode) + } + val secondaryUserDir = Environment.buildPath( + context.filesDir, + ID, + userId.toString(), + SHARED_PREFS, + fileName + ) + + return context.getSharedPreferences(secondaryUserDir, mode) + } + + /** + * Remove dirs for deleted users. + */ + @VisibleForTesting + internal fun clearDeletedUserData() { + backgroundExecutor.execute { + val file = Environment.buildPath(context.filesDir, ID) + if (!file.exists()) return@execute + val aliveUsers = userManager.aliveUsers.map { it.id.toString() } + val dirsToDelete = file.list().filter { !aliveUsers.contains(it) } + + dirsToDelete.forEach { dir -> + try { + val dirToDelete = Environment.buildPath( + file, + dir, + ) + dirToDelete.deleteRecursively() + } catch (e: Exception) { + Log.e(ID, "Deletion failed.", e) + } + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java b/packages/SystemUI/src/com/android/systemui/settings/dagger/MultiUserUtilsModule.java index 7084d3ffc9ff..2f62e44ba4c4 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java +++ b/packages/SystemUI/src/com/android/systemui/settings/dagger/MultiUserUtilsModule.java @@ -21,25 +21,28 @@ import android.content.Context; import android.os.Handler; import android.os.UserManager; +import com.android.systemui.CoreStartable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dump.DumpManager; import com.android.systemui.settings.UserContentResolverProvider; import com.android.systemui.settings.UserContextProvider; +import com.android.systemui.settings.UserFileManager; +import com.android.systemui.settings.UserFileManagerImpl; import com.android.systemui.settings.UserTracker; import com.android.systemui.settings.UserTrackerImpl; import dagger.Binds; import dagger.Module; import dagger.Provides; +import dagger.multibindings.ClassKey; +import dagger.multibindings.IntoMap; /** * Dagger Module for classes found within the com.android.systemui.settings package. */ @Module -public abstract class SettingsModule { - - +public abstract class MultiUserUtilsModule { @Binds @SysUISingleton abstract UserContextProvider bindUserContextProvider(UserTracker tracker); @@ -62,4 +65,12 @@ public abstract class SettingsModule { tracker.initialize(startingUser); return tracker; } + + @Binds + @IntoMap + @ClassKey(UserFileManagerImpl.class) + abstract CoreStartable bindUserFileManagerCoreStartable(UserFileManagerImpl sysui); + + @Binds + abstract UserFileManager bindUserFileManager(UserFileManagerImpl impl); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 9e029095ea6b..ca147286a301 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -900,16 +900,36 @@ public class KeyguardIndicationController { mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState); } } else { - if (!mAccessibilityManager.isEnabled() - && !mAccessibilityManager.isTouchExplorationEnabled() - && mKeyguardUpdateMonitor.isUdfpsSupported() - && mKeyguardUpdateMonitor.getUserCanSkipBouncer( - KeyguardUpdateMonitor.getCurrentUser())) { - final int stringId = mKeyguardUpdateMonitor.getIsFaceAuthenticated() - ? R.string.keyguard_face_successful_unlock_press - : R.string.keyguard_unlock_press; - showBiometricMessage(mContext.getString(stringId)); + final boolean canSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer( + KeyguardUpdateMonitor.getCurrentUser()); + if (canSkipBouncer) { + final boolean faceAuthenticated = mKeyguardUpdateMonitor.getIsFaceAuthenticated(); + final boolean udfpsSupported = mKeyguardUpdateMonitor.isUdfpsSupported(); + final boolean a11yEnabled = mAccessibilityManager.isEnabled() + || mAccessibilityManager.isTouchExplorationEnabled(); + if (udfpsSupported && faceAuthenticated) { // co-ex + if (a11yEnabled) { + showBiometricMessage(mContext.getString( + R.string.keyguard_face_successful_unlock_swipe)); + } else { + showBiometricMessage(mContext.getString( + R.string.keyguard_face_successful_unlock_press)); + } + } else if (faceAuthenticated) { // face-only + showBiometricMessage(mContext.getString( + R.string.keyguard_face_successful_unlock_swipe)); + } else if (udfpsSupported) { // udfps-only + if (a11yEnabled) { + showBiometricMessage(mContext.getString(R.string.keyguard_unlock)); + } else { + showBiometricMessage(mContext.getString( + R.string.keyguard_unlock_press)); + } + } else { // no security or unlocked by a trust agent + showBiometricMessage(mContext.getString(R.string.keyguard_unlock)); + } } else { + // suggest swiping up for the primary authentication bouncer showBiometricMessage(mContext.getString(R.string.keyguard_unlock)); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.kt index a57440c95271..f662a040fae6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.kt @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.notification.collection import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.statusbar.notification.NotifPipelineFlags import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderEntryListener import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderGroupListener import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderListListener @@ -250,4 +249,4 @@ class NotifPipeline @Inject constructor( fun getInternalNotifUpdater(name: String?): InternalNotifUpdater { return mNotifCollection.getInternalNotifUpdater(name) } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt index 5a281b130347..657c394d4e30 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt @@ -145,4 +145,4 @@ class ViewConfigCoordinator @Inject internal constructor( private const val TAG = "ViewConfigCoordinator" private val DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG) } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java index 7dd3672a6e30..a7719d3d82a4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnUserInteractionCallbackImpl.java @@ -23,6 +23,7 @@ import android.service.notification.NotificationStats; import androidx.annotation.NonNull; +import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason; @@ -33,10 +34,13 @@ import com.android.systemui.statusbar.notification.collection.render.Notificatio import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback; import com.android.systemui.statusbar.policy.HeadsUpManager; +import javax.inject.Inject; + /** * Callback for when a user interacts with a {@see ExpandableNotificationRow}. Sends relevant * information about the interaction to the notification pipeline. */ +@SysUISingleton public class OnUserInteractionCallbackImpl implements OnUserInteractionCallback { private final NotificationVisibilityProvider mVisibilityProvider; private final NotifCollection mNotifCollection; @@ -44,6 +48,7 @@ public class OnUserInteractionCallbackImpl implements OnUserInteractionCallback private final StatusBarStateController mStatusBarStateController; private final VisualStabilityCoordinator mVisualStabilityCoordinator; + @Inject public OnUserInteractionCallbackImpl( NotificationVisibilityProvider visibilityProvider, NotifCollection notifCollection, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationPresenterExtensions.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationPresenterExtensions.java deleted file mode 100644 index bdbb0eb48e8a..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationPresenterExtensions.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2010 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.notification.collection.legacy; - -import static com.android.systemui.statusbar.phone.CentralSurfaces.SPEW; - -import android.service.notification.StatusBarNotification; -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.android.internal.statusbar.NotificationVisibility; -import com.android.systemui.statusbar.notification.NotificationEntryListener; -import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource; - -import org.jetbrains.annotations.NotNull; - -import javax.inject.Inject; - -/** - * This is some logic extracted from the - * {@link com.android.systemui.statusbar.phone.StatusBarNotificationPresenter} - * into a class that implements a new-pipeline interface so that the new pipeline can implement it - * correctly. - * - * Specifically, this is the logic which updates notifications when uiMode and screen properties - * change, and which closes the shade when the last notification disappears. - */ -public class LegacyNotificationPresenterExtensions implements NotifShadeEventSource { - private static final String TAG = "LegacyNotifPresenter"; - private final NotificationEntryManager mEntryManager; - private boolean mEntryListenerAdded; - private Runnable mShadeEmptiedCallback; - private Runnable mNotifRemovedByUserCallback; - - @Inject - public LegacyNotificationPresenterExtensions(NotificationEntryManager entryManager) { - mEntryManager = entryManager; - } - - private void ensureEntryListenerAdded() { - if (mEntryListenerAdded) return; - mEntryListenerAdded = true; - mEntryManager.addNotificationEntryListener(new NotificationEntryListener() { - @Override - public void onEntryRemoved( - @NotNull NotificationEntry entry, - NotificationVisibility visibility, - boolean removedByUser, - int reason) { - StatusBarNotification old = entry.getSbn(); - if (SPEW) { - Log.d(TAG, "removeNotification key=" + entry.getKey() - + " old=" + old + " reason=" + reason); - } - - if (old != null && !mEntryManager.hasActiveNotifications()) { - if (mShadeEmptiedCallback != null) mShadeEmptiedCallback.run(); - } - if (removedByUser) { - if (mNotifRemovedByUserCallback != null) mNotifRemovedByUserCallback.run(); - } - } - }); - } - - @Override - public void setNotifRemovedByUserCallback(@NonNull Runnable callback) { - if (mNotifRemovedByUserCallback != null) { - throw new IllegalStateException("mNotifRemovedByUserCallback already set"); - } - mNotifRemovedByUserCallback = callback; - ensureEntryListenerAdded(); - } - - @Override - public void setShadeEmptiedCallback(@NonNull Runnable callback) { - if (mShadeEmptiedCallback != null) { - throw new IllegalStateException("mShadeEmptiedCallback already set"); - } - mShadeEmptiedCallback = callback; - ensureEntryListenerAdded(); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnUserInteractionCallbackImplLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnUserInteractionCallbackImplLegacy.java deleted file mode 100644 index 103b14b09e9c..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnUserInteractionCallbackImplLegacy.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2020 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.notification.collection.legacy; - -import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL; - -import android.service.notification.NotificationListenerService; -import android.service.notification.NotificationStats; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; -import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; -import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; -import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback; -import com.android.systemui.statusbar.policy.HeadsUpManager; - -/** - * Callback for when a user interacts with a {@see ExpandableNotificationRow}. - */ -public class OnUserInteractionCallbackImplLegacy implements OnUserInteractionCallback { - private final NotificationEntryManager mNotificationEntryManager; - private final NotificationVisibilityProvider mVisibilityProvider; - private final HeadsUpManager mHeadsUpManager; - private final StatusBarStateController mStatusBarStateController; - private final VisualStabilityManager mVisualStabilityManager; - private final GroupMembershipManager mGroupMembershipManager; - - public OnUserInteractionCallbackImplLegacy( - NotificationEntryManager notificationEntryManager, - NotificationVisibilityProvider visibilityProvider, - HeadsUpManager headsUpManager, - StatusBarStateController statusBarStateController, - VisualStabilityManager visualStabilityManager, - GroupMembershipManager groupMembershipManager - ) { - mNotificationEntryManager = notificationEntryManager; - mVisibilityProvider = visibilityProvider; - mHeadsUpManager = headsUpManager; - mStatusBarStateController = statusBarStateController; - mVisualStabilityManager = visualStabilityManager; - mGroupMembershipManager = groupMembershipManager; - } - - /** - * Callback triggered when a user: - * 1. Manually dismisses a notification {@see ExpandableNotificationRow}. - * 2. Clicks on a notification with flag {@link android.app.Notification#FLAG_AUTO_CANCEL}. - * {@see StatusBarNotificationActivityStarter} - * - * @param groupSummaryToDismiss the group summary that should be dismissed - * along with this dismissal. If null, does not additionally - * dismiss any notifications. - */ - private void onDismiss( - NotificationEntry entry, - @NotificationListenerService.NotificationCancelReason int cancellationReason, - @Nullable NotificationEntry groupSummaryToDismiss - ) { - int dismissalSurface = NotificationStats.DISMISSAL_SHADE; - if (mHeadsUpManager.isAlerting(entry.getKey())) { - dismissalSurface = NotificationStats.DISMISSAL_PEEK; - } else if (mStatusBarStateController.isDozing()) { - dismissalSurface = NotificationStats.DISMISSAL_AOD; - } - - if (groupSummaryToDismiss != null) { - onDismiss(groupSummaryToDismiss, cancellationReason, null); - } - - mNotificationEntryManager.performRemoveNotification( - entry.getSbn(), - new DismissedByUserStats( - dismissalSurface, - DISMISS_SENTIMENT_NEUTRAL, - mVisibilityProvider.obtain(entry, true)), - cancellationReason - ); - - } - - @Override - public void onImportanceChanged(NotificationEntry entry) { - mVisualStabilityManager.temporarilyAllowReordering(); - } - - /** - * @param entry that is being dismissed - * @return the group summary to dismiss along with this entry if this is the last entry in - * the group. Else, returns null. - */ - @Nullable - private NotificationEntry getGroupSummaryToDismiss(NotificationEntry entry) { - if (mGroupMembershipManager.isOnlyChildInGroup(entry)) { - NotificationEntry groupSummary = mGroupMembershipManager.getLogicalGroupSummary(entry); - return groupSummary.isDismissable() ? groupSummary : null; - } - return null; - } - - @Override - @NonNull - public Runnable registerFutureDismissal(@NonNull NotificationEntry entry, - @CancellationReason int cancellationReason) { - NotificationEntry groupSummaryToDismiss = getGroupSummaryToDismiss(entry); - return () -> onDismiss(entry, cancellationReason, groupSummaryToDismiss); - } -} - diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/NotificationVisibilityProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/NotificationVisibilityProviderImpl.kt index 6a1e36f4f469..ec10aaf3cfe3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/NotificationVisibilityProviderImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/NotificationVisibilityProviderImpl.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.collection.provider import com.android.internal.statusbar.NotificationVisibility +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection @@ -25,6 +26,7 @@ import com.android.systemui.statusbar.notification.logging.NotificationLogger import javax.inject.Inject /** pipeline-agnostic implementation for getting [NotificationVisibility]. */ +@SysUISingleton class NotificationVisibilityProviderImpl @Inject constructor( private val notifDataStore: NotifLiveDataStore, private val notifCollection: CommonNotifCollection @@ -46,4 +48,4 @@ class NotificationVisibilityProviderImpl @Inject constructor( NotificationLogger.getNotificationLocation(notifCollection.getEntry(key)) private fun getCount() = notifDataStore.activeNotifCount.value -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java index a2cb9509a621..1b3f83d1892f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.collection.render; +import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotifPipeline; @@ -28,10 +29,13 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.Set; +import javax.inject.Inject; + /** * Provides grouping information for notification entries including information about a group's * expanded state. */ +@SysUISingleton public class GroupExpansionManagerImpl implements GroupExpansionManager, Coordinator { private final GroupMembershipManager mGroupMembershipManager; private final Set<OnGroupExpansionChangeListener> mOnGroupChangeListeners = new HashSet<>(); @@ -39,6 +43,7 @@ public class GroupExpansionManagerImpl implements GroupExpansionManager, Coordin // Set of summary keys whose groups are expanded private final Set<NotificationEntry> mExpandedGroups = new HashSet<>(); + @Inject public GroupExpansionManagerImpl(GroupMembershipManager groupMembershipManager) { mGroupMembershipManager = groupMembershipManager; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 27a7cd779405..d838252aa362 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -41,23 +41,19 @@ import com.android.systemui.statusbar.notification.AssistantFeedbackController; import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger; -import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl; import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore; import com.android.systemui.statusbar.notification.collection.NotifLiveDataStoreImpl; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotifPipelineChoreographerModule; import com.android.systemui.statusbar.notification.collection.coordinator.ShadeEventCoordinator; -import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator; import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorsModule; import com.android.systemui.statusbar.notification.collection.inflation.BindEventManager; import com.android.systemui.statusbar.notification.collection.inflation.BindEventManagerImpl; import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; import com.android.systemui.statusbar.notification.collection.inflation.OnUserInteractionCallbackImpl; -import com.android.systemui.statusbar.notification.collection.legacy.LegacyNotificationPresenterExtensions; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; -import com.android.systemui.statusbar.notification.collection.legacy.OnUserInteractionCallbackImplLegacy; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; @@ -90,7 +86,6 @@ import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotifPanelEventsModule; import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.leak.LeakDetector; import com.android.systemui.wmshell.BubblesManager; @@ -116,12 +111,10 @@ import dagger.Provides; }) public interface NotificationsModule { @Binds - StackScrollAlgorithm.SectionProvider bindSectionProvider( - NotificationSectionsManager impl); + StackScrollAlgorithm.SectionProvider bindSectionProvider(NotificationSectionsManager impl); @Binds - StackScrollAlgorithm.BypassController bindBypassController( - KeyguardBypassController impl); + StackScrollAlgorithm.BypassController bindBypassController(KeyguardBypassController impl); /** Provides an instance of {@link NotificationEntryManager} */ @SysUISingleton @@ -194,12 +187,8 @@ public interface NotificationsModule { } /** Provides an instance of {@link NotifGutsViewManager} */ - @SysUISingleton - @Provides - static NotifGutsViewManager provideNotifGutsViewManager( - NotificationGutsManager notificationGutsManager) { - return notificationGutsManager; - } + @Binds + NotifGutsViewManager bindNotifGutsViewManager(NotificationGutsManager notificationGutsManager); /** Provides an instance of {@link VisualStabilityManager} */ @SysUISingleton @@ -253,25 +242,13 @@ public interface NotificationsModule { /** Provides an instance of {@link GroupMembershipManager} */ @SysUISingleton @Provides - static GroupMembershipManager provideGroupMembershipManager( - NotifPipelineFlags notifPipelineFlags, - Lazy<NotificationGroupManagerLegacy> groupManagerLegacy) { - return notifPipelineFlags.isNewPipelineEnabled() - ? new GroupMembershipManagerImpl() - : groupManagerLegacy.get(); + static GroupMembershipManager provideGroupMembershipManager() { + return new GroupMembershipManagerImpl(); } /** Provides an instance of {@link GroupExpansionManager} */ - @SysUISingleton - @Provides - static GroupExpansionManager provideGroupExpansionManager( - NotifPipelineFlags notifPipelineFlags, - Lazy<GroupMembershipManager> groupMembershipManager, - Lazy<NotificationGroupManagerLegacy> groupManagerLegacy) { - return notifPipelineFlags.isNewPipelineEnabled() - ? new GroupExpansionManagerImpl(groupMembershipManager.get()) - : groupManagerLegacy.get(); - } + @Binds + GroupExpansionManager provideGroupExpansionManager(GroupExpansionManagerImpl impl); /** Initializes the notification data pipeline (can be disabled via config). */ @SysUISingleton @@ -290,69 +267,28 @@ public interface NotificationsModule { /** * Provide the active notification collection managing the notifications to render. */ - @Provides - @SysUISingleton - static CommonNotifCollection provideCommonNotifCollection( - NotifPipelineFlags notifPipelineFlags, - Lazy<NotifPipeline> pipeline, - NotificationEntryManager entryManager) { - return notifPipelineFlags.isNewPipelineEnabled() - ? pipeline.get() : entryManager; - } + @Binds + CommonNotifCollection provideCommonNotifCollection(NotifPipeline pipeline); /** * Provide the object which can be used to obtain NotificationVisibility objects. */ @Binds - @SysUISingleton NotificationVisibilityProvider provideNotificationVisibilityProvider( - NotificationVisibilityProviderImpl newProvider); + NotificationVisibilityProviderImpl impl); /** * Provide the active implementation for presenting notifications. */ - @Provides - @SysUISingleton - static NotifShadeEventSource provideNotifShadeEventSource( - NotifPipelineFlags notifPipelineFlags, - Lazy<ShadeEventCoordinator> shadeEventCoordinatorLazy, - Lazy<LegacyNotificationPresenterExtensions> legacyNotificationPresenterExtensionsLazy) { - return notifPipelineFlags.isNewPipelineEnabled() - ? shadeEventCoordinatorLazy.get() - : legacyNotificationPresenterExtensionsLazy.get(); - } + @Binds + NotifShadeEventSource provideNotifShadeEventSource(ShadeEventCoordinator shadeEventCoordinator); /** * Provide a dismissal callback that's triggered when a user manually dismissed a notification * from the notification shade or it gets auto-cancelled by click. */ - @Provides - @SysUISingleton - static OnUserInteractionCallback provideOnUserInteractionCallback( - NotifPipelineFlags notifPipelineFlags, - HeadsUpManager headsUpManager, - StatusBarStateController statusBarStateController, - Lazy<NotifCollection> notifCollection, - Lazy<NotificationVisibilityProvider> visibilityProvider, - Lazy<VisualStabilityCoordinator> visualStabilityCoordinator, - NotificationEntryManager entryManager, - VisualStabilityManager visualStabilityManager, - Lazy<GroupMembershipManager> groupMembershipManagerLazy) { - return notifPipelineFlags.isNewPipelineEnabled() - ? new OnUserInteractionCallbackImpl( - visibilityProvider.get(), - notifCollection.get(), - headsUpManager, - statusBarStateController, - visualStabilityCoordinator.get()) - : new OnUserInteractionCallbackImplLegacy( - entryManager, - visibilityProvider.get(), - headsUpManager, - statusBarStateController, - visualStabilityManager, - groupMembershipManagerLazy.get()); - } + @Binds + OnUserInteractionCallback provideOnUserInteractionCallback(OnUserInteractionCallbackImpl impl); /** */ @Binds diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 2fd02d9f1cd9..defae5b6941f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.stack; import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING; +import static com.android.internal.jank.InteractionJankMonitor.CUJ_SHADE_CLEAR_ALL; import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT; import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE; import static com.android.systemui.util.DumpUtilsKt.println; @@ -5246,6 +5247,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable setClearAllInProgress(true); mShadeNeedsToClose = closeShade; + InteractionJankMonitor.getInstance().begin(this, CUJ_SHADE_CLEAR_ALL); // Decrease the delay for every row we animate to give the sense of // accelerating the swipes final int rowDelayDecrement = 5; @@ -6158,6 +6160,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private void onClearAllAnimationsEnd( List<ExpandableNotificationRow> viewsToRemove, @SelectedRows int selectedRows) { + InteractionJankMonitor.getInstance().end(CUJ_SHADE_CLEAR_ALL); if (mClearAllAnimationListener != null) { mClearAllAnimationListener.onAnimationEnd(viewsToRemove, selectedRows); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index a0d940e835ff..1182fb370280 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -28,7 +28,6 @@ import static com.android.systemui.statusbar.notification.stack.NotificationStac import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_HIGH_PRIORITY; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.SelectedRows; -import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.canChildBeCleared; import static com.android.systemui.statusbar.phone.NotificationIconAreaController.HIGH_PRIORITY; import android.content.res.Configuration; @@ -38,12 +37,10 @@ import android.graphics.PointF; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; -import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.util.Log; import android.util.Pair; import android.view.Display; -import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; @@ -53,20 +50,17 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.ExpandHelper; import com.android.systemui.Gefingerpoken; import com.android.systemui.R; import com.android.systemui.SwipeHelper; import com.android.systemui.classifier.Classifier; import com.android.systemui.classifier.FalsingCollector; -import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.media.KeyguardMediaController; @@ -85,9 +79,7 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.LaunchAnimationParameters; -import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotificationActivityStarter; -import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifPipeline; @@ -163,13 +155,10 @@ public class NotificationStackScrollLayoutController { private final Resources mResources; private final NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder; private final ScrimController mScrimController; - private final NotifPipelineFlags mNotifPipelineFlags; private final NotifPipeline mNotifPipeline; private final NotifCollection mNotifCollection; private final NotificationEntryManager mNotificationEntryManager; - private final IStatusBarService mIStatusBarService; private final UiEventLogger mUiEventLogger; - private final LayoutInflater mLayoutInflater; private final NotificationRemoteInputManager mRemoteInputManager; private final VisualStabilityManager mVisualStabilityManager; private final ShadeController mShadeController; @@ -206,8 +195,6 @@ public class NotificationStackScrollLayoutController { @Nullable private NotificationActivityStarter mNotificationActivityStarter; - private ColorExtractor.OnColorsChangedListener mOnColorsChangedListener; - @VisibleForTesting final View.OnAttachStateChangeListener mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() { @@ -256,10 +243,7 @@ public class NotificationStackScrollLayoutController { mView.setAnimateBottomOnLayout(true); } // Let's update the footer once the notifications have been updated (in the next frame) - mView.post(() -> { - updateFooter(); - updateSectionBoundaries("dynamic privacy changed"); - }); + mView.post(this::updateFooter); }; @VisibleForTesting @@ -634,7 +618,6 @@ public class NotificationStackScrollLayoutController { KeyguardMediaController keyguardMediaController, KeyguardBypassController keyguardBypassController, ZenModeController zenModeController, - SysuiColorExtractor colorExtractor, NotificationLockscreenUserManager lockscreenUserManager, MetricsLogger metricsLogger, DumpManager dumpManager, @@ -647,15 +630,12 @@ public class NotificationStackScrollLayoutController { NotificationGroupManagerLegacy legacyGroupManager, GroupExpansionManager groupManager, @SilentHeader SectionHeaderController silentHeaderController, - NotifPipelineFlags notifPipelineFlags, NotifPipeline notifPipeline, NotifCollection notifCollection, NotificationEntryManager notificationEntryManager, LockscreenShadeTransitionController lockscreenShadeTransitionController, ShadeTransitionController shadeTransitionController, - IStatusBarService iStatusBarService, UiEventLogger uiEventLogger, - LayoutInflater layoutInflater, NotificationRemoteInputManager remoteInputManager, VisualStabilityManager visualStabilityManager, ShadeController shadeController, @@ -698,14 +678,11 @@ public class NotificationStackScrollLayoutController { mCentralSurfaces.requestNotificationUpdate("onGroupsChanged"); } }); - mNotifPipelineFlags = notifPipelineFlags; mSilentHeaderController = silentHeaderController; mNotifPipeline = notifPipeline; mNotifCollection = notifCollection; mNotificationEntryManager = notificationEntryManager; - mIStatusBarService = iStatusBarService; mUiEventLogger = uiEventLogger; - mLayoutInflater = layoutInflater; mRemoteInputManager = remoteInputManager; mVisualStabilityManager = visualStabilityManager; mShadeController = shadeController; @@ -745,21 +722,12 @@ public class NotificationStackScrollLayoutController { .setOnMenuEventListener(mMenuEventListener) .build(); - if (mNotifPipelineFlags.isNewPipelineEnabled()) { - mNotifPipeline.addCollectionListener(new NotifCollectionListener() { - @Override - public void onEntryUpdated(NotificationEntry entry) { - mView.onEntryUpdated(entry); - } - }); - } else { - mNotificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() { - @Override - public void onPreEntryUpdated(NotificationEntry entry) { - mView.onEntryUpdated(entry); - } - }); - } + mNotifPipeline.addCollectionListener(new NotifCollectionListener() { + @Override + public void onEntryUpdated(NotificationEntry entry) { + mView.onEntryUpdated(entry); + } + }); mView.initView(mView.getContext(), mSwipeHelper, mNotificationStackSizeCalculator); mView.setKeyguardBypassEnabled(mKeyguardBypassController.getBypassEnabled()); @@ -1231,10 +1199,6 @@ public class NotificationStackScrollLayoutController { Trace.endSection(); } - public boolean areNotificationsHiddenInShade() { - return mZenModeController.areNotificationsHiddenInShade(); - } - public boolean isShowingEmptyShadeView() { return mShowEmptyShadeView; } @@ -1339,15 +1303,6 @@ public class NotificationStackScrollLayoutController { }; } - public void updateSectionBoundaries(String reason) { - if (mNotifPipelineFlags.isNewPipelineEnabled()) { - return; - } - Trace.beginSection("NSSLC.updateSectionBoundaries"); - mView.updateSectionBoundaries(reason); - Trace.endSection(); - } - public void updateFooter() { Trace.beginSection("NSSLC.updateFooter"); mView.updateFooter(); @@ -1463,39 +1418,18 @@ public class NotificationStackScrollLayoutController { private void onAnimationEnd(List<ExpandableNotificationRow> viewsToRemove, @SelectedRows int selectedRows) { - if (mNotifPipelineFlags.isNewPipelineEnabled()) { - if (selectedRows == ROWS_ALL) { - mNotifCollection.dismissAllNotifications( - mLockscreenUserManager.getCurrentUserId()); - } else { - final List<Pair<NotificationEntry, DismissedByUserStats>> - entriesWithRowsDismissedFromShade = new ArrayList<>(); - for (ExpandableNotificationRow row : viewsToRemove) { - final NotificationEntry entry = row.getEntry(); - entriesWithRowsDismissedFromShade.add( - new Pair<>(entry, getDismissedByUserStats(entry))); - } - mNotifCollection.dismissNotifications(entriesWithRowsDismissedFromShade); - } + if (selectedRows == ROWS_ALL) { + mNotifCollection.dismissAllNotifications( + mLockscreenUserManager.getCurrentUserId()); } else { - for (ExpandableNotificationRow rowToRemove : viewsToRemove) { - if (canChildBeCleared(rowToRemove)) { - mNotificationEntryManager.performRemoveNotification( - rowToRemove.getEntry().getSbn(), - getDismissedByUserStats(rowToRemove.getEntry()), - NotificationListenerService.REASON_CANCEL_ALL); - } else { - rowToRemove.resetTranslation(); - } - } - if (selectedRows == ROWS_ALL) { - try { - // TODO(b/169585328): Do not clear media player notifications - mIStatusBarService.onClearAllNotifications( - mLockscreenUserManager.getCurrentUserId()); - } catch (Exception ignored) { - } + final List<Pair<NotificationEntry, DismissedByUserStats>> + entriesWithRowsDismissedFromShade = new ArrayList<>(); + for (ExpandableNotificationRow row : viewsToRemove) { + final NotificationEntry entry = row.getEntry(); + entriesWithRowsDismissedFromShade.add( + new Pair<>(entry, getDismissedByUserStats(entry))); } + mNotifCollection.dismissNotifications(entriesWithRowsDismissedFromShade); } } 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 9f65350ec0fd..a8486fae38e1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -1167,9 +1167,6 @@ public class CentralSurfacesImpl extends CoreStartable implements mStatusBarTouchableRegionManager.setup(this, mNotificationShadeWindowView); mHeadsUpManager.addListener(mNotificationPanelViewController.getOnHeadsUpChangedListener()); - if (!mNotifPipelineFlags.isNewPipelineEnabled()) { - mHeadsUpManager.addListener(mVisualStabilityManager); - } mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager); createNavigationBar(result); @@ -4336,9 +4333,6 @@ public class CentralSurfacesImpl extends CoreStartable implements Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration()); } - if (!mNotifPipelineFlags.isNewPipelineEnabled()) { - mViewHierarchyManager.updateRowStates(); - } mScreenPinningRequest.onConfigurationChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaViewController.kt new file mode 100644 index 000000000000..3942dae7e0c3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaViewController.kt @@ -0,0 +1,34 @@ +/* + * 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.statusbar.phone + +import com.android.systemui.util.ViewController +import javax.inject.Inject + +class KeyguardBottomAreaViewController @Inject constructor(view: KeyguardBottomAreaView) : + ViewController<KeyguardBottomAreaView> (view) { + override fun onViewAttached() { + } + + override fun onViewDetached() { + } + + fun getView(): KeyguardBottomAreaView { + // TODO: remove this method. + return mView + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index ed3d4ad8ad5d..0001cd0a2798 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -266,6 +266,9 @@ public class KeyguardBouncer { private void setVisibility(@View.Visibility int visibility) { mContainer.setVisibility(visibility); + if (mKeyguardViewController != null) { + mKeyguardViewController.onBouncerVisibilityChanged(visibility); + } dispatchVisibilityChanged(); } @@ -397,10 +400,6 @@ public class KeyguardBouncer { return mShowingSoon || mExpansion != EXPANSION_HIDDEN && mExpansion != EXPANSION_VISIBLE; } - public boolean getShowingSoon() { - return mShowingSoon; - } - /** * @return {@code true} when bouncer's pre-hide animation already started but isn't completely * hidden yet, {@code false} otherwise. @@ -645,7 +644,7 @@ public class KeyguardBouncer { /** * Invoked when the bouncer expansion reaches {@link KeyguardBouncer#EXPANSION_VISIBLE}. * This is NOT called each time the bouncer is shown, but rather only when the fully - * shown amount has changed based on the panel expansion. The bouncer is visibility + * shown amount has changed based on the panel expansion. The bouncer's visibility * can still change when the expansion amount hasn't changed. * See {@link KeyguardBouncer#isShowing()} for the checks for the bouncer showing state. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index b257d14dc4d5..a89b62cc2520 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -343,6 +343,8 @@ public final class NotificationPanelViewController extends PanelViewController { private final LockIconViewController mLockIconViewController; private NotificationsQuickSettingsContainer mNotificationContainerParent; private final NotificationsQSContainerController mNotificationsQSContainerController; + private final Provider<KeyguardBottomAreaViewController> + mKeyguardBottomAreaViewControllerProvider; private boolean mAnimateNextPositionUpdate; private float mQuickQsHeaderHeight; private final ScreenOffAnimationController mScreenOffAnimationController; @@ -741,6 +743,7 @@ public final class NotificationPanelViewController extends PanelViewController { InteractionJankMonitor interactionJankMonitor, QsFrameTranslateController qsFrameTranslateController, SysUiState sysUiState, + Provider<KeyguardBottomAreaViewController> keyguardBottomAreaViewControllerProvider, KeyguardUnlockAnimationController keyguardUnlockAnimationController, NotificationListContainer notificationListContainer, PanelEventsEmitter panelEventsEmitter, @@ -782,6 +785,7 @@ public final class NotificationPanelViewController extends PanelViewController { mNotificationsQSContainerController = notificationsQSContainerController; mNotificationListContainer = notificationListContainer; mNotificationStackSizeCalculator = notificationStackSizeCalculator; + mKeyguardBottomAreaViewControllerProvider = keyguardBottomAreaViewControllerProvider; mNotificationsQSContainerController.init(); mNotificationStackScrollLayoutController = notificationStackScrollLayoutController; mNotificationIconAreaController = notificationIconAreaController; @@ -1222,8 +1226,7 @@ public final class NotificationPanelViewController extends PanelViewController { int index = mView.indexOfChild(mKeyguardBottomArea); mView.removeView(mKeyguardBottomArea); KeyguardBottomAreaView oldBottomArea = mKeyguardBottomArea; - mKeyguardBottomArea = (KeyguardBottomAreaView) mLayoutInflater.inflate( - R.layout.keyguard_bottom_area, mView, false); + mKeyguardBottomArea = mKeyguardBottomAreaViewControllerProvider.get().getView(); mKeyguardBottomArea.initFrom(oldBottomArea); mView.addView(mKeyguardBottomArea, index); initBottomArea(); @@ -3918,7 +3921,6 @@ public final class NotificationPanelViewController extends PanelViewController { * {@link ShadeViewManager}. */ public void updateNotificationViews(String reason) { - mNotificationStackScrollLayoutController.updateSectionBoundaries(reason); mNotificationStackScrollLayoutController.updateFooter(); mNotificationIconAreaController.updateNotificationIcons(createVisibleEntriesList()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index d2fc1af010b9..0e278d225074 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -599,9 +599,7 @@ public abstract class PanelViewController { float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) { if (target == mExpandedHeight && mOverExpansion == 0.0f) { // We're at the target and didn't fling and there's no overshoot - endJankMonitoring(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE); - mKeyguardStateController.notifyPanelFlingEnd(); - notifyExpandingFinished(); + onFlingEnd(false /* cancelled */); return; } mIsFlinging = true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index d250022102e9..b5e43021a6e4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -965,7 +965,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public boolean bouncerIsOrWillBeShowing() { - return isBouncerShowing() || mBouncer.getShowingSoon(); + return isBouncerShowing() || mBouncer.inTransit(); } public boolean isFullscreenBouncer() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index cf776e3b60d1..72db884b4cac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -52,21 +52,15 @@ import com.android.systemui.EventLogTags; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.assist.AssistManager; import com.android.systemui.plugins.ActivityStarter; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationClickNotifier; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotificationActivityStarter; -import com.android.systemui.statusbar.notification.NotificationEntryListener; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; -import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -92,24 +86,19 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte private final Context mContext; - private final CommandQueue mCommandQueue; private final Handler mMainThreadHandler; private final Executor mUiBgExecutor; - private final NotificationEntryManager mEntryManager; - private final NotifPipeline mNotifPipeline; private final NotificationVisibilityProvider mVisibilityProvider; private final HeadsUpManagerPhone mHeadsUpManager; private final ActivityStarter mActivityStarter; private final NotificationClickNotifier mClickNotifier; - private final StatusBarStateController mStatusBarStateController; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final KeyguardManager mKeyguardManager; private final IDreamManager mDreamManager; private final Optional<BubblesManager> mBubblesManagerOptional; private final Lazy<AssistManager> mAssistManagerLazy; private final NotificationRemoteInputManager mRemoteInputManager; - private final GroupMembershipManager mGroupMembershipManager; private final NotificationLockscreenUserManager mLockscreenUserManager; private final ShadeController mShadeController; private final KeyguardStateController mKeyguardStateController; @@ -118,7 +107,6 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte private final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback; private final ActivityIntentHelper mActivityIntentHelper; - private final NotifPipelineFlags mNotifPipelineFlags; private final MetricsLogger mMetricsLogger; private final StatusBarNotificationActivityStarterLogger mLogger; @@ -134,23 +122,19 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte @Inject StatusBarNotificationActivityStarter( Context context, - CommandQueue commandQueue, Handler mainThreadHandler, Executor uiBgExecutor, - NotificationEntryManager entryManager, NotifPipeline notifPipeline, NotificationVisibilityProvider visibilityProvider, HeadsUpManagerPhone headsUpManager, ActivityStarter activityStarter, NotificationClickNotifier clickNotifier, - StatusBarStateController statusBarStateController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, KeyguardManager keyguardManager, IDreamManager dreamManager, Optional<BubblesManager> bubblesManagerOptional, Lazy<AssistManager> assistManagerLazy, NotificationRemoteInputManager remoteInputManager, - GroupMembershipManager groupMembershipManager, NotificationLockscreenUserManager lockscreenUserManager, ShadeController shadeController, KeyguardStateController keyguardStateController, @@ -158,7 +142,6 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte LockPatternUtils lockPatternUtils, StatusBarRemoteInputCallback remoteInputCallback, ActivityIntentHelper activityIntentHelper, - NotifPipelineFlags notifPipelineFlags, MetricsLogger metricsLogger, StatusBarNotificationActivityStarterLogger logger, OnUserInteractionCallback onUserInteractionCallback, @@ -168,23 +151,18 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte ActivityLaunchAnimator activityLaunchAnimator, NotificationLaunchAnimatorControllerProvider notificationAnimationProvider) { mContext = context; - mCommandQueue = commandQueue; mMainThreadHandler = mainThreadHandler; mUiBgExecutor = uiBgExecutor; - mEntryManager = entryManager; - mNotifPipeline = notifPipeline; mVisibilityProvider = visibilityProvider; mHeadsUpManager = headsUpManager; mActivityStarter = activityStarter; mClickNotifier = clickNotifier; - mStatusBarStateController = statusBarStateController; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mKeyguardManager = keyguardManager; mDreamManager = dreamManager; mBubblesManagerOptional = bubblesManagerOptional; mAssistManagerLazy = assistManagerLazy; mRemoteInputManager = remoteInputManager; - mGroupMembershipManager = groupMembershipManager; mLockscreenUserManager = lockscreenUserManager; mShadeController = shadeController; mKeyguardStateController = keyguardStateController; @@ -192,7 +170,6 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte mLockPatternUtils = lockPatternUtils; mStatusBarRemoteInputCallback = remoteInputCallback; mActivityIntentHelper = activityIntentHelper; - mNotifPipelineFlags = notifPipelineFlags; mMetricsLogger = metricsLogger; mLogger = logger; mOnUserInteractionCallback = onUserInteractionCallback; @@ -203,21 +180,12 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte mActivityLaunchAnimator = activityLaunchAnimator; mNotificationAnimationProvider = notificationAnimationProvider; - if (!mNotifPipelineFlags.isNewPipelineEnabled()) { - mEntryManager.addNotificationEntryListener(new NotificationEntryListener() { - @Override - public void onPendingEntryAdded(NotificationEntry entry) { - handleFullScreenIntent(entry); - } - }); - } else { - mNotifPipeline.addCollectionListener(new NotifCollectionListener() { - @Override - public void onEntryAdded(NotificationEntry entry) { - handleFullScreenIntent(entry); - } - }); - } + notifPipeline.addCollectionListener(new NotifCollectionListener() { + @Override + public void onEntryAdded(NotificationEntry entry) { + handleFullScreenIntent(entry); + } + }); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index bd69cc3869c2..aebf0b5325ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -30,13 +30,9 @@ import android.util.Log; import android.util.Slog; import android.view.View; import android.view.accessibility.AccessibilityManager; -import android.widget.TextView; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.statusbar.IStatusBarService; -import com.android.internal.widget.MessagingGroup; -import com.android.internal.widget.MessagingMessage; -import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.Dependency; import com.android.systemui.ForegroundServiceNotificationListener; import com.android.systemui.InitController; @@ -57,7 +53,6 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.AboveShelfObserver; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotifPipelineFlags; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource; @@ -72,16 +67,12 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; -import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; -import java.util.List; - import javax.inject.Inject; @CentralSurfacesComponent.CentralSurfacesScope class StatusBarNotificationPresenter implements NotificationPresenter, - ConfigurationController.ConfigurationListener, NotificationRowBinderImpl.BindRowCallback, CommandQueue.Callbacks { private static final String TAG = "StatusBarNotificationPresenter"; @@ -92,10 +83,8 @@ class StatusBarNotificationPresenter implements NotificationPresenter, private final NotificationLockscreenUserManager mLockscreenUserManager; private final SysuiStatusBarStateController mStatusBarStateController; private final NotifShadeEventSource mNotifShadeEventSource; - private final NotificationEntryManager mEntryManager; private final NotificationMediaManager mMediaManager; private final NotificationGutsManager mGutsManager; - private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final LockscreenGestureLogger mLockscreenGestureLogger; private final NotificationPanelViewController mNotificationPanel; @@ -116,9 +105,6 @@ class StatusBarNotificationPresenter implements NotificationPresenter, private final IStatusBarService mBarService; private final DynamicPrivacyController mDynamicPrivacyController; private final NotificationListContainer mNotifListContainer; - private boolean mReinflateNotificationsOnUserSwitched; - private boolean mDispatchUiModeChangeOnUserSwitched; - private TextView mNotificationPanelDebugText; protected boolean mVrMode; @@ -143,15 +129,12 @@ class StatusBarNotificationPresenter implements NotificationPresenter, NotificationLockscreenUserManager lockscreenUserManager, SysuiStatusBarStateController sysuiStatusBarStateController, NotifShadeEventSource notifShadeEventSource, - NotificationEntryManager notificationEntryManager, NotificationMediaManager notificationMediaManager, NotificationGutsManager notificationGutsManager, - KeyguardUpdateMonitor keyguardUpdateMonitor, LockscreenGestureLogger lockscreenGestureLogger, InitController initController, NotificationInterruptStateProvider notificationInterruptStateProvider, NotificationRemoteInputManager remoteInputManager, - ConfigurationController configurationController, NotifPipelineFlags notifPipelineFlags, NotificationRemoteInputManager.Callback remoteInputManagerCallback, NotificationListContainer notificationListContainer) { @@ -170,10 +153,8 @@ class StatusBarNotificationPresenter implements NotificationPresenter, mLockscreenUserManager = lockscreenUserManager; mStatusBarStateController = sysuiStatusBarStateController; mNotifShadeEventSource = notifShadeEventSource; - mEntryManager = notificationEntryManager; mMediaManager = notificationMediaManager; mGutsManager = notificationGutsManager; - mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockscreenGestureLogger = lockscreenGestureLogger; mAboveShelfObserver = new AboveShelfObserver(stackScrollerController.getView()); mNotificationShadeWindowController = notificationShadeWindowController; @@ -208,11 +189,6 @@ class StatusBarNotificationPresenter implements NotificationPresenter, mNotifListContainer); mNotifShadeEventSource.setShadeEmptiedCallback(this::maybeClosePanelForShadeEmptied); mNotifShadeEventSource.setNotifRemovedByUserCallback(this::maybeEndAmbientPulse); - if (!mNotifPipelineFlags.isNewPipelineEnabled()) { - mEntryManager.setUpWithPresenter(this); - mEntryManager.addNotificationLifetimeExtender(mHeadsUpManager); - mEntryManager.addNotificationLifetimeExtender(mGutsManager); - } notificationInterruptStateProvider.addSuppressor(mInterruptSuppressor); mLockscreenUserManager.setUpWithPresenter(this); mMediaManager.setUpWithPresenter(this); @@ -225,7 +201,6 @@ class StatusBarNotificationPresenter implements NotificationPresenter, onUserSwitched(mLockscreenUserManager.getCurrentUserId()); }); - configurationController.addCallback(this); } /** Called when the shade has been emptied to attempt to close the shade */ @@ -240,65 +215,6 @@ class StatusBarNotificationPresenter implements NotificationPresenter, } @Override - public void onDensityOrFontScaleChanged() { - // TODO(b/145659174): Remove legacy pipeline code - if (mNotifPipelineFlags.isNewPipelineEnabled()) return; - MessagingMessage.dropCache(); - MessagingGroup.dropCache(); - if (!mKeyguardUpdateMonitor.isSwitchingUser()) { - updateNotificationsOnDensityOrFontScaleChanged(); - } else { - mReinflateNotificationsOnUserSwitched = true; - } - } - - @Override - public void onUiModeChanged() { - // TODO(b/145659174): Remove legacy pipeline code - if (mNotifPipelineFlags.isNewPipelineEnabled()) return; - if (!mKeyguardUpdateMonitor.isSwitchingUser()) { - updateNotificationsOnUiModeChanged(); - } else { - mDispatchUiModeChangeOnUserSwitched = true; - } - } - - @Override - public void onThemeChanged() { - onDensityOrFontScaleChanged(); - } - - private void updateNotificationsOnUiModeChanged() { - // TODO(b/145659174): Remove legacy pipeline code - if (mNotifPipelineFlags.isNewPipelineEnabled()) return; - List<NotificationEntry> userNotifications = - mEntryManager.getActiveNotificationsForCurrentUser(); - for (int i = 0; i < userNotifications.size(); i++) { - NotificationEntry entry = userNotifications.get(i); - ExpandableNotificationRow row = entry.getRow(); - if (row != null) { - row.onUiModeChanged(); - } - } - } - - private void updateNotificationsOnDensityOrFontScaleChanged() { - // TODO(b/145659174): Remove legacy pipeline code - if (mNotifPipelineFlags.isNewPipelineEnabled()) return; - List<NotificationEntry> userNotifications = - mEntryManager.getActiveNotificationsForCurrentUser(); - for (int i = 0; i < userNotifications.size(); i++) { - NotificationEntry entry = userNotifications.get(i); - entry.onDensityOrFontScaleChanged(); - boolean exposedGuts = entry.areGutsExposed(); - if (exposedGuts) { - mGutsManager.onDensityOrFontScaleChanged(entry); - } - } - } - - - @Override public boolean isCollapsing() { return mNotificationPanel.isCollapsing() || mNotificationShadeWindowController.isLaunchingActivity(); @@ -338,17 +254,6 @@ class StatusBarNotificationPresenter implements NotificationPresenter, // End old BaseStatusBar.userSwitched if (MULTIUSER_DEBUG) mNotificationPanel.setHeaderDebugInfo("USER " + newUserId); mCommandQueue.animateCollapsePanels(); - if (!mNotifPipelineFlags.isNewPipelineEnabled()) { - if (mReinflateNotificationsOnUserSwitched) { - updateNotificationsOnDensityOrFontScaleChanged(); - mReinflateNotificationsOnUserSwitched = false; - } - if (mDispatchUiModeChangeOnUserSwitched) { - updateNotificationsOnUiModeChanged(); - mDispatchUiModeChangeOnUserSwitched = false; - } - updateNotificationViews("user switched"); - } mMediaManager.clearCurrentMediaNotification(); mCentralSurfaces.setLockscreenUser(newUserId); updateMediaMetaData(true, false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java index 06532c4f9d17..ea4ecd5f5ab4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java @@ -42,6 +42,7 @@ import com.android.systemui.statusbar.connectivity.NetworkController; import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.phone.KeyguardBottomAreaView; import com.android.systemui.statusbar.phone.NotificationIconAreaController; import com.android.systemui.statusbar.phone.NotificationPanelView; import com.android.systemui.statusbar.phone.NotificationPanelViewController; @@ -290,4 +291,17 @@ public abstract class StatusBarViewModule { secureSettings, mainExecutor); } + + /** + * Constructs a new, unattached {@link KeyguardBottomAreaView}. + * + * Note that this is explicitly _not_ a singleton, as we want to be able to reinflate it + */ + @Provides + public static KeyguardBottomAreaView providesKeyguardBottomAreaView( + NotificationPanelView npv, LayoutInflater layoutInflater) { + return (KeyguardBottomAreaView) layoutInflater.inflate(R + .layout.keyguard_bottom_area, npv, false); + } + } diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java index c99ad23ab23d..0b5594b14d0e 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java @@ -16,8 +16,6 @@ package com.android.systemui.tv; -import android.content.Context; - import com.android.systemui.SystemUIFactory; import com.android.systemui.dagger.GlobalRootComponent; @@ -27,9 +25,7 @@ import com.android.systemui.dagger.GlobalRootComponent; */ public class TvSystemUIFactory extends SystemUIFactory { @Override - protected GlobalRootComponent buildGlobalRootComponent(Context context) { - return DaggerTvGlobalRootComponent.builder() - .context(context) - .build(); + protected GlobalRootComponent.Builder getGlobalRootComponentBuilder() { + return DaggerTvGlobalRootComponent.builder(); } } diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java index 36a49af2276a..f1e89ac81b1b 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java @@ -46,6 +46,7 @@ import com.android.systemui.qs.dagger.QSModule; import com.android.systemui.qs.tileimpl.QSFactoryImpl; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsImplementation; +import com.android.systemui.screenshot.ReferenceScreenshotModule; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationLockscreenUserManager; @@ -91,6 +92,7 @@ import dagger.multibindings.IntoSet; GestureModule.class, PowerModule.class, QSModule.class, + ReferenceScreenshotModule.class, VolumeModule.class, }, subcomponents = { diff --git a/packages/SystemUI/src/com/android/systemui/util/InitializationChecker.kt b/packages/SystemUI/src/com/android/systemui/util/InitializationChecker.kt new file mode 100644 index 000000000000..f53b6824d45d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/InitializationChecker.kt @@ -0,0 +1,38 @@ +/* + * 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.util + +import android.app.ActivityThread +import android.os.Process +import com.android.systemui.dagger.qualifiers.InstrumentationTest +import javax.inject.Inject + +/** + * Used to check whether SystemUI should be fully initialized. + */ +class InitializationChecker @Inject constructor( + @InstrumentationTest private val instrumentationTest: Boolean +) { + + /** + * Only initialize components for the main system ui process running as the primary user + */ + fun initializeComponents(): Boolean = + !instrumentationTest && + Process.myUserHandle().isSystem && + ActivityThread.currentProcessName() == ActivityThread.currentPackageName() +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java index ac1a83c269e0..4021652295c1 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -31,6 +32,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableResources; import android.view.Gravity; +import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -42,6 +44,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -104,6 +107,17 @@ public class KeyguardHostViewControllerTest extends SysuiTestCase { } @Test + public void onBouncerVisible_propagatesToKeyguardSecurityContainerController() { + mKeyguardHostViewController.onBouncerVisibilityChanged(ViewGroup.VISIBLE); + mKeyguardHostViewController.onBouncerVisibilityChanged(ViewGroup.INVISIBLE); + + InOrder order = inOrder(mKeyguardSecurityContainerController); + order.verify(mKeyguardSecurityContainerController).onBouncerVisibilityChanged(View.VISIBLE); + order.verify(mKeyguardSecurityContainerController).onBouncerVisibilityChanged( + View.INVISIBLE); + } + + @Test public void testGravityReappliedOnConfigurationChange() { FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java index bc351427310d..68e49c0a1d4b 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java @@ -25,17 +25,21 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; 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.verify; import static org.mockito.Mockito.when; import android.content.res.Configuration; import android.content.res.Resources; +import android.hardware.biometrics.BiometricSourceType; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.MotionEvent; +import android.view.View; import android.view.WindowInsetsController; import androidx.test.filters.SmallTest; @@ -46,6 +50,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.biometrics.SidefpsController; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.log.SessionTracker; @@ -59,10 +64,14 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.Optional; + @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper() @@ -124,6 +133,14 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { private SessionTracker mSessionTracker; @Mock private KeyguardViewController mKeyguardViewController; + @Mock + private SidefpsController mSidefpsController; + @Mock + private KeyguardPasswordViewController mKeyguardPasswordViewControllerMock; + + @Captor + private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback; + private Configuration mConfiguration; private KeyguardSecurityContainerController mKeyguardSecurityContainerController; @@ -160,7 +177,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { mKeyguardStateController, mKeyguardSecurityViewFlipperController, mConfigurationController, mFalsingCollector, mFalsingManager, mUserSwitcherController, mFeatureFlags, mGlobalSettings, - mSessionTracker).create(mSecurityCallback); + mSessionTracker, Optional.of(mSidefpsController)).create(mSecurityCallback); } @Test @@ -258,9 +275,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @Test public void showSecurityScreen_twoHandedMode_flagEnabled_noOneHandedMode() { when(mResources.getBoolean(R.bool.can_use_one_handed_bouncer)).thenReturn(true); - when(mKeyguardSecurityViewFlipperController.getSecurityView( - eq(SecurityMode.Password), any(KeyguardSecurityCallback.class))) - .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewController); + setupGetSecurityView(); mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password); verify(mView).initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager, @@ -276,4 +291,126 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { verify(mUserSwitcherController) .removeUserSwitchCallback(any(UserSwitcherController.UserSwitchCallback.class)); } + + @Test + public void onBouncerVisibilityChanged_allConditionsGood_sideFpsHintShown() { + setupConditionsToEnableSideFpsHint(); + reset(mSidefpsController); + + mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); + + verify(mSidefpsController).show(); + verify(mSidefpsController, never()).hide(); + } + + @Test + public void onBouncerVisibilityChanged_fpsSensorNotRunning_sideFpsHintHidden() { + setupConditionsToEnableSideFpsHint(); + setFingerprintDetectionRunning(false); + reset(mSidefpsController); + + mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); + + verify(mSidefpsController).hide(); + verify(mSidefpsController, never()).show(); + } + + @Test + public void onBouncerVisibilityChanged_withoutSidedSecurity_sideFpsHintHidden() { + setupConditionsToEnableSideFpsHint(); + setSidedSecurityMode(false); + reset(mSidefpsController); + + mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); + + verify(mSidefpsController).hide(); + verify(mSidefpsController, never()).show(); + } + + @Test + public void onBouncerVisibilityChanged_needsStrongAuth_sideFpsHintHidden() { + setupConditionsToEnableSideFpsHint(); + setNeedsStrongAuth(true); + reset(mSidefpsController); + + mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); + + verify(mSidefpsController).hide(); + verify(mSidefpsController, never()).show(); + } + + @Test + public void onBouncerVisibilityChanged_sideFpsHintShown_sideFpsHintHidden() { + setupGetSecurityView(); + setupConditionsToEnableSideFpsHint(); + mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); + verify(mSidefpsController, atLeastOnce()).show(); + reset(mSidefpsController); + + mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.INVISIBLE); + + verify(mSidefpsController).hide(); + verify(mSidefpsController, never()).show(); + } + + @Test + public void onStartingToHide_sideFpsHintShown_sideFpsHintHidden() { + setupGetSecurityView(); + setupConditionsToEnableSideFpsHint(); + mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); + verify(mSidefpsController, atLeastOnce()).show(); + reset(mSidefpsController); + + mKeyguardSecurityContainerController.onStartingToHide(); + + verify(mSidefpsController).hide(); + verify(mSidefpsController, never()).show(); + } + + @Test + public void onPause_sideFpsHintShown_sideFpsHintHidden() { + setupGetSecurityView(); + setupConditionsToEnableSideFpsHint(); + mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); + verify(mSidefpsController, atLeastOnce()).show(); + reset(mSidefpsController); + + mKeyguardSecurityContainerController.onPause(); + + verify(mSidefpsController).hide(); + verify(mSidefpsController, never()).show(); + } + + private void setupConditionsToEnableSideFpsHint() { + attachView(); + setSidedSecurityMode(true); + setFingerprintDetectionRunning(true); + setNeedsStrongAuth(false); + } + + private void attachView() { + mKeyguardSecurityContainerController.onViewAttached(); + verify(mKeyguardUpdateMonitor).registerCallback(mKeyguardUpdateMonitorCallback.capture()); + } + + private void setFingerprintDetectionRunning(boolean running) { + when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(running); + mKeyguardUpdateMonitorCallback.getValue().onBiometricRunningStateChanged(running, + BiometricSourceType.FINGERPRINT); + } + + private void setSidedSecurityMode(boolean sided) { + when(mView.isSidedSecurityMode()).thenReturn(sided); + } + + private void setNeedsStrongAuth(boolean needed) { + when(mKeyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(needed); + mKeyguardUpdateMonitorCallback.getValue().onStrongAuthStateChanged(/* userId= */ 0); + } + + private void setupGetSecurityView() { + when(mKeyguardSecurityViewFlipperController.getSecurityView( + any(), any(KeyguardSecurityCallback.class))) + .thenReturn((KeyguardInputViewController) mKeyguardPasswordViewControllerMock); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt index b61fbbe1ea75..273786d74782 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt @@ -207,25 +207,30 @@ ViewHierarchyAnimatorTest : SysuiTestCase() { } @Test - fun animatesAppearingViewsFromStartToEnd() { - // Starting GONE. - rootView.visibility = View.GONE - rootView.layout(0 /* l */, 50 /* t */, 50 /* r */, 100 /* b */) - var success = ViewHierarchyAnimator.animateAddition(rootView) - rootView.visibility = View.VISIBLE - rootView.layout(0 /* l */, 100 /* t */, 100 /* r */, 200 /* b */) + fun animatesInvisibleViews() { + rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */) + rootView.visibility = View.INVISIBLE + + val success = ViewHierarchyAnimator.animate(rootView) + // Change all bounds. + rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */) assertTrue(success) assertNotNull(rootView.getTag(R.id.tag_animator)) - checkBounds(rootView, l = 50, t = 150, r = 50, b = 150) + // The initial values should be those of the previous layout. + checkBounds(rootView, l = 10, t = 10, r = 50, b = 50) endAnimation(rootView) assertNull(rootView.getTag(R.id.tag_animator)) - checkBounds(rootView, l = 0, t = 100, r = 100, b = 200) + // The end values should be those of the latest layout. + checkBounds(rootView, l = 0, t = 15, r = 70, b = 80) + } - // Starting INVISIBLE. - rootView.visibility = View.INVISIBLE + @Test + fun animatesAppearingViewsFromStartToEnd() { + // Starting GONE. + rootView.visibility = View.GONE rootView.layout(0 /* l */, 50 /* t */, 50 /* r */, 100 /* b */) - success = ViewHierarchyAnimator.animateAddition(rootView) + var success = ViewHierarchyAnimator.animateAddition(rootView) rootView.visibility = View.VISIBLE rootView.layout(0 /* l */, 100 /* t */, 100 /* r */, 200 /* b */) @@ -937,7 +942,7 @@ ViewHierarchyAnimatorTest : SysuiTestCase() { } @Test - fun doesNotAnimateInvisibleViews() { + fun doesNotAnimateGoneViews() { rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */) // GONE @@ -948,15 +953,6 @@ ViewHierarchyAnimatorTest : SysuiTestCase() { assertFalse(success) assertNull(rootView.getTag(R.id.tag_animator)) checkBounds(rootView, l = 0, t = 15, r = 55, b = 80) - - // INVISIBLE. - rootView.visibility = View.INVISIBLE - success = ViewHierarchyAnimator.animate(rootView) - rootView.layout(0 /* l */, 20 /* t */, 10 /* r */, 50 /* b */) - - assertFalse(success) - assertNull(rootView.getTag(R.id.tag_animator)) - checkBounds(rootView, l = 0, t = 20, r = 10, b = 50) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/biometrics/OWNERS new file mode 100644 index 000000000000..adb10f01b5e1 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/OWNERS @@ -0,0 +1,4 @@ +set noparent + +include /services/core/java/com/android/server/biometrics/OWNERS +beverlyt@google.com diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt index dec2b82ed88f..6157ccbd597a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt @@ -62,7 +62,6 @@ import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.eq import org.mockito.Captor import org.mockito.Mock -import org.mockito.Mockito.`when` import org.mockito.Mockito.any import org.mockito.Mockito.anyFloat import org.mockito.Mockito.anyInt @@ -72,6 +71,7 @@ import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.times import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` as whenEver import org.mockito.junit.MockitoJUnit private const val DISPLAY_ID = 2 @@ -126,15 +126,15 @@ class SidefpsControllerTest : SysuiTestCase() { context.addMockSystemService(DisplayManager::class.java, displayManager) context.addMockSystemService(WindowManager::class.java, windowManager) - `when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sidefpsView) - `when`(sidefpsView.findViewById<LottieAnimationView>(eq(R.id.sidefps_animation))) + whenEver(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sidefpsView) + whenEver(sidefpsView.findViewById<LottieAnimationView>(eq(R.id.sidefps_animation))) .thenReturn(mock(LottieAnimationView::class.java)) with(mock(ViewPropertyAnimator::class.java)) { - `when`(sidefpsView.animate()).thenReturn(this) - `when`(alpha(anyFloat())).thenReturn(this) - `when`(setStartDelay(anyLong())).thenReturn(this) - `when`(setDuration(anyLong())).thenReturn(this) - `when`(setListener(any())).thenAnswer { + whenEver(sidefpsView.animate()).thenReturn(this) + whenEver(alpha(anyFloat())).thenReturn(this) + whenEver(setStartDelay(anyLong())).thenReturn(this) + whenEver(setDuration(anyLong())).thenReturn(this) + whenEver(setListener(any())).thenAnswer { (it.arguments[0] as Animator.AnimatorListener) .onAnimationEnd(mock(Animator::class.java)) this @@ -177,7 +177,7 @@ class SidefpsControllerTest : SysuiTestCase() { displayBounds = Rect(0, 0, displayWidth, displayHeight) var locations = listOf(sensorLocation) - `when`(fingerprintManager.sensorPropertiesInternal).thenReturn( + whenEver(fingerprintManager.sensorPropertiesInternal).thenReturn( listOf( FingerprintSensorPropertiesInternal( SENSOR_ID, @@ -196,12 +196,12 @@ class SidefpsControllerTest : SysuiTestCase() { displayInfo.initInfo() val dmGlobal = mock(DisplayManagerGlobal::class.java) val display = Display(dmGlobal, DISPLAY_ID, displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS) - `when`(dmGlobal.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(displayInfo) - `when`(windowManager.defaultDisplay).thenReturn(display) - `when`(windowManager.maximumWindowMetrics).thenReturn( + whenEver(dmGlobal.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(displayInfo) + whenEver(windowManager.defaultDisplay).thenReturn(display) + whenEver(windowManager.maximumWindowMetrics).thenReturn( WindowMetrics(displayBounds, WindowInsets.CONSUMED) ) - `when`(windowManager.currentWindowMetrics).thenReturn( + whenEver(windowManager.currentWindowMetrics).thenReturn( WindowMetrics(displayBounds, windowInsets) ) @@ -277,13 +277,13 @@ class SidefpsControllerTest : SysuiTestCase() { @Test fun testShowsForMostSettings() = testWithDisplay { - `when`(activityTaskManager.getTasks(anyInt())).thenReturn(listOf(fpEnrollTask())) + whenEver(activityTaskManager.getTasks(anyInt())).thenReturn(listOf(fpEnrollTask())) testIgnoredFor(REASON_AUTH_SETTINGS, ignored = false) } @Test fun testIgnoredForVerySpecificSettings() = testWithDisplay { - `when`(activityTaskManager.getTasks(anyInt())).thenReturn(listOf(fpSettingsTask())) + whenEver(activityTaskManager.getTasks(anyInt())).thenReturn(listOf(fpSettingsTask())) testIgnoredFor(REASON_AUTH_SETTINGS) } @@ -424,6 +424,20 @@ class SidefpsControllerTest : SysuiTestCase() { assertThat(overlayViewParamsCaptor.value.x).isEqualTo(displayWidth - boundsWidth) assertThat(overlayViewParamsCaptor.value.y).isEqualTo(sensorLocation.sensorLocationY) } + + @Test + fun hasSideFpsSensor_withSensorProps_returnsTrue() = testWithDisplay { + // By default all those tests assume the side fps sensor is available. + + assertThat(fingerprintManager.hasSideFpsSensor()).isTrue() + } + + @Test + fun hasSideFpsSensor_withoutSensorProps_returnsFalse() { + whenEver(fingerprintManager.sensorPropertiesInternal).thenReturn(null) + + assertThat(fingerprintManager.hasSideFpsSensor()).isFalse() + } } private fun insetsForSmallNavbar() = insetsWithBottom(60) diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java index 7ab49584f0e3..e1eda117177d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java @@ -32,7 +32,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.app.PendingIntent; -import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.testing.AndroidTestingRunner; @@ -115,7 +114,7 @@ public class ActionProxyReceiverTest extends SysuiTestCase { actionProxyReceiver.onReceive(mContext, mIntent); verify(mMockScreenshotSmartActions, never()) - .notifyScreenshotAction(any(Context.class), anyString(), anyString(), anyBoolean(), + .notifyScreenshotAction(anyString(), anyString(), anyBoolean(), any(Intent.class)); } @@ -129,7 +128,7 @@ public class ActionProxyReceiverTest extends SysuiTestCase { actionProxyReceiver.onReceive(mContext, mIntent); verify(mMockScreenshotSmartActions).notifyScreenshotAction( - mContext, testId, ACTION_TYPE_SHARE, false, null); + testId, ACTION_TYPE_SHARE, false, null); } private ActionProxyReceiver constructActionProxyReceiver(boolean withStatusBar) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DeleteScreenshotReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DeleteScreenshotReceiverTest.java index 664c125533d1..d58f47a0469a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DeleteScreenshotReceiverTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DeleteScreenshotReceiverTest.java @@ -31,7 +31,6 @@ import static org.mockito.Mockito.verify; import android.content.ContentResolver; import android.content.ContentValues; -import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; @@ -81,7 +80,7 @@ public class DeleteScreenshotReceiverTest extends SysuiTestCase { verify(mMockExecutor, never()).execute(any(Runnable.class)); verify(mMockScreenshotSmartActions, never()).notifyScreenshotAction( - any(Context.class), any(String.class), any(String.class), anyBoolean(), + any(String.class), any(String.class), anyBoolean(), any(Intent.class)); } @@ -113,7 +112,7 @@ public class DeleteScreenshotReceiverTest extends SysuiTestCase { } // ensure smart actions not called by default - verify(mMockScreenshotSmartActions, never()).notifyScreenshotAction(any(Context.class), + verify(mMockScreenshotSmartActions, never()).notifyScreenshotAction( any(String.class), any(String.class), anyBoolean(), any(Intent.class)); } @@ -129,7 +128,7 @@ public class DeleteScreenshotReceiverTest extends SysuiTestCase { mDeleteScreenshotReceiver.onReceive(mContext, intent); verify(mMockExecutor).execute(any(Runnable.class)); - verify(mMockScreenshotSmartActions).notifyScreenshotAction(mContext, testId, + verify(mMockScreenshotSmartActions).notifyScreenshotAction(testId, ACTION_TYPE_DELETE, false, null); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java index 3d658ec8e811..69b7b88b0524 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java @@ -43,7 +43,6 @@ import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; -import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition; @@ -71,7 +70,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { public void setup() { mSmartActionsProvider = mock( ScreenshotNotificationSmartActionsProvider.class); - mScreenshotSmartActions = new ScreenshotSmartActions(); + mScreenshotSmartActions = new ScreenshotSmartActions(() -> mSmartActionsProvider); mHandler = mock(Handler.class); } @@ -158,8 +157,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { Bitmap bitmap = mock(Bitmap.class); when(bitmap.getConfig()).thenReturn(Bitmap.Config.HARDWARE); ScreenshotNotificationSmartActionsProvider actionsProvider = - SystemUIFactory.getInstance().createScreenshotNotificationSmartActionsProvider( - mContext, null, mHandler); + new ScreenshotNotificationSmartActionsProvider(); CompletableFuture<List<Notification.Action>> smartActionsFuture = mScreenshotSmartActions.getSmartActionsFuture("", null, bitmap, actionsProvider, REGULAR_SMART_ACTIONS, @@ -183,7 +181,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { data.mActionsReadyListener = null; SaveImageInBackgroundTask task = new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data, - ActionTransition::new); + ActionTransition::new, mSmartActionsProvider); Notification.Action shareAction = task.createShareAction(mContext, mContext.getResources(), Uri.parse("Screenshot_123.png")).get().action; @@ -211,7 +209,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { data.mActionsReadyListener = null; SaveImageInBackgroundTask task = new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data, - ActionTransition::new); + ActionTransition::new, mSmartActionsProvider); Notification.Action editAction = task.createEditAction(mContext, mContext.getResources(), Uri.parse("Screenshot_123.png")).get().action; @@ -239,7 +237,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { data.mActionsReadyListener = null; SaveImageInBackgroundTask task = new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data, - ActionTransition::new); + ActionTransition::new, mSmartActionsProvider); Notification.Action deleteAction = task.createDeleteAction(mContext, mContext.getResources(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java index 011e6b7b1071..83c949793447 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SmartActionsReceiverTest.java @@ -74,6 +74,6 @@ public class SmartActionsReceiverTest extends SysuiTestCase { verify(mMockPendingIntent).send( eq(mContext), eq(0), isNull(), isNull(), isNull(), isNull(), any(Bundle.class)); verify(mMockScreenshotSmartActions).notifyScreenshotAction( - mContext, testId, testActionType, true, intent); + testId, testActionType, true, intent); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt new file mode 100644 index 000000000000..73226fa0b12c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt @@ -0,0 +1,120 @@ +/* + * 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.settings + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.IntentFilter +import android.os.Environment +import android.os.UserManager +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.time.FakeSystemClock +import com.google.common.truth.Truth.assertThat +import java.util.concurrent.Executor +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.isNull +import org.mockito.Mockito.spy +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class UserFileManagerImplTest : SysuiTestCase() { + companion object { + const val TEST_FILE_NAME = "abc.txt" + } + + lateinit var userFileManager: UserFileManagerImpl + lateinit var backgroundExecutor: FakeExecutor + @Mock + lateinit var userManager: UserManager + @Mock + lateinit var broadcastDispatcher: BroadcastDispatcher + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + backgroundExecutor = FakeExecutor(FakeSystemClock()) + userFileManager = UserFileManagerImpl(context, userManager, + broadcastDispatcher, backgroundExecutor) + } + + @Test + fun testGetFile() { + assertThat(userFileManager.getFile(TEST_FILE_NAME, 0).path) + .isEqualTo("${context.filesDir}/$TEST_FILE_NAME") + assertThat(userFileManager.getFile(TEST_FILE_NAME, 11).path) + .isEqualTo("${context.filesDir}/${UserFileManagerImpl.ID}/11/files/$TEST_FILE_NAME") + } + + @Test + fun testGetSharedPreferences() { + assertThat(userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 0)) + .isNotEqualTo(userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 11)) + } + + @Test + fun testUserFileManagerStart() { + val userFileManager = spy(userFileManager) + userFileManager.start() + verify(userFileManager).clearDeletedUserData() + verify(broadcastDispatcher).registerReceiver(any(BroadcastReceiver::class.java), + any(IntentFilter::class.java), + any(Executor::class.java), isNull(), eq(Context.RECEIVER_EXPORTED), isNull()) + } + + @Test + fun testClearDeletedUserData() { + val dir = Environment.buildPath( + context.filesDir, + UserFileManagerImpl.ID, + "11", + "files" + ) + dir.mkdirs() + val file = Environment.buildPath( + context.filesDir, + UserFileManagerImpl.ID, + "11", + "files", + TEST_FILE_NAME + ) + val secondaryUserDir = Environment.buildPath( + context.filesDir, + UserFileManagerImpl.ID, + "11", + ) + file.createNewFile() + assertThat(secondaryUserDir.exists()).isTrue() + assertThat(file.exists()).isTrue() + userFileManager.clearDeletedUserData() + assertThat(backgroundExecutor.runAllReady()).isGreaterThan(0) + verify(userManager).aliveUsers + assertThat(secondaryUserDir.exists()).isFalse() + assertThat(file.exists()).isFalse() + dir.deleteRecursively() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java index d67e26f138f2..9c25462b7c0d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java @@ -30,6 +30,7 @@ import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewCont import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRANSIENT; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_USER_LOCKED; +import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON; import static com.google.common.truth.Truth.assertThat; @@ -212,7 +213,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { R.string.do_financed_disclosure_with_name, ORGANIZATION_NAME); when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); - when(mScreenLifecycle.getScreenState()).thenReturn(ScreenLifecycle.SCREEN_ON); + when(mScreenLifecycle.getScreenState()).thenReturn(SCREEN_ON); when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true); when(mIndicationArea.findViewById(R.id.keyguard_indication_text_bottom)) @@ -954,64 +955,170 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { } @Test - public void nonBypassFaceSuccess_touchExplorationEnabled_showsSwipeToOpen() { - // GIVEN non bypass face auth and touch exploration is enabled - when(mKeyguardBypassController.canBypass()).thenReturn(false); - when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true); + public void coEx_faceSuccess_showsPressToOpen() { + // GIVEN bouncer isn't showing, can skip bouncer, udfps is supported, no a11y enabled when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); + when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(KeyguardUpdateMonitor.getCurrentUser())) + .thenReturn(true); + when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true); + when(mAccessibilityManager.isEnabled()).thenReturn(false); + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false); + createController(); + mController.setVisible(true); + + // WHEN face auth succeeds + when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(true); + mController.getKeyguardCallback().onBiometricAuthenticated(0, + BiometricSourceType.FACE, false); + + // THEN 'face unlocked. press unlock icon to open' message shows + String pressToOpen = mContext.getString(R.string.keyguard_face_successful_unlock_press); + verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, pressToOpen); + + assertThat(mTextView.getText()).isNotEqualTo(pressToOpen); + } + + + @Test + public void coEx_faceSuccess_touchExplorationEnabled_showsFaceUnlockedSwipeToOpen() { + // GIVEN bouncer isn't showing, can skip bouncer, udfps is supported, a11y enabled + when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); + when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(KeyguardUpdateMonitor.getCurrentUser())) + .thenReturn(true); + when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true); + when(mAccessibilityManager.isEnabled()).thenReturn(true); + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true); createController(); - String swipeToOpen = mContext.getString(R.string.keyguard_unlock); mController.setVisible(true); // WHEN face authenticated + when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(true); mController.getKeyguardCallback().onBiometricAuthenticated(0, BiometricSourceType.FACE, false); - // THEN show 'swipe up to open' message - verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, swipeToOpen); + // THEN show 'face unlocked. swipe up to open' message + String faceUnlockedSwipeToOpen = + mContext.getString(R.string.keyguard_face_successful_unlock_swipe); + verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, faceUnlockedSwipeToOpen); } @Test - public void nonBypassFaceSuccess_a11yEnabled_showsSwipeToOpen() { - // GIVEN non bypass face auth and a11y is enabled - when(mKeyguardBypassController.canBypass()).thenReturn(false); + public void coEx_faceSuccess_a11yEnabled_showsFaceUnlockedSwipeToOpen() { + // GIVEN bouncer isn't showing, can skip bouncer, udfps is supported, a11y is enabled + when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); + when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(KeyguardUpdateMonitor.getCurrentUser())) + .thenReturn(true); + when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true); when(mAccessibilityManager.isEnabled()).thenReturn(true); + createController(); + mController.setVisible(true); + + // WHEN face auth is successful + when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(true); + mController.getKeyguardCallback().onBiometricAuthenticated(0, + BiometricSourceType.FACE, false); + + // THEN show 'swipe up to open' message + String faceUnlockedSwipeToOpen = + mContext.getString(R.string.keyguard_face_successful_unlock_swipe); + verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, faceUnlockedSwipeToOpen); + } + + @Test + public void faceOnly_faceSuccess_showsFaceUnlockedSwipeToOpen() { + // GIVEN bouncer isn't showing, can skip bouncer, no udfps supported when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); + when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(KeyguardUpdateMonitor.getCurrentUser())) + .thenReturn(true); + when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(false); createController(); - String swipeToOpen = mContext.getString(R.string.keyguard_unlock); mController.setVisible(true); // WHEN face auth is successful + when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(true); mController.getKeyguardCallback().onBiometricAuthenticated(0, BiometricSourceType.FACE, false); // THEN show 'swipe up to open' message + String faceUnlockedSwipeToOpen = + mContext.getString(R.string.keyguard_face_successful_unlock_swipe); + verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, faceUnlockedSwipeToOpen); + } + + @Test + public void udfpsOnly_a11yEnabled_showsSwipeToOpen() { + // GIVEN bouncer isn't showing, can skip bouncer, udfps is supported, a11y is enabled + when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); + when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(KeyguardUpdateMonitor.getCurrentUser())) + .thenReturn(true); + when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true); + when(mAccessibilityManager.isEnabled()).thenReturn(true); + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true); + createController(); + mController.setVisible(true); + + // WHEN showActionToUnlock + mController.showActionToUnlock(); + + // THEN show 'swipe up to open' message + String swipeToOpen = mContext.getString(R.string.keyguard_unlock); verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, swipeToOpen); } @Test - public void coEx_nonBypassFaceSuccess_showsPressLockIcon() { - // GIVEN udfps is supported, non-bypass face auth, and no a11y enabled + public void udfpsOnly_showsPressToOpen() { + // GIVEN bouncer isn't showing, udfps is supported, a11y is NOT enabled, can skip bouncer + when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); + when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(KeyguardUpdateMonitor.getCurrentUser())) + .thenReturn(true); when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true); - when(mKeyguardBypassController.canBypass()).thenReturn(false); - when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(true); when(mAccessibilityManager.isEnabled()).thenReturn(false); when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false); + createController(); + mController.setVisible(true); + + // WHEN showActionToUnlock + mController.showActionToUnlock(); + + // THEN show 'press unlock icon to open' message + String pressToOpen = mContext.getString(R.string.keyguard_unlock_press); + verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, pressToOpen); + } + + @Test + public void canSkipBouncer_noSecurity_showSwipeToUnlockHint() { + // GIVEN bouncer isn't showing, can skip bouncer, no security (udfps isn't supported, + // face wasn't authenticated) when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(KeyguardUpdateMonitor.getCurrentUser())) .thenReturn(true); + when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(false); createController(); mController.setVisible(true); - // WHEN face auth succeeds - mController.getKeyguardCallback().onBiometricAuthenticated(0, - BiometricSourceType.FACE, false); + // WHEN showActionToUnlock + mController.showActionToUnlock(); - // THEN press unlock icon to open message shows - String pressLockIcon = mContext.getString(R.string.keyguard_face_successful_unlock_press); - verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, pressLockIcon); + // THEN show 'swipe up to open' message + String swipeToOpen = mContext.getString(R.string.keyguard_unlock); + verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, swipeToOpen); + } - assertThat(mTextView.getText()).isNotEqualTo(pressLockIcon); + @Test + public void cannotSkipBouncer_showSwipeToUnlockHint() { + // GIVEN bouncer isn't showing and cannot skip bouncer + when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); + when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(KeyguardUpdateMonitor.getCurrentUser())) + .thenReturn(false); + createController(); + mController.setVisible(true); + + // WHEN showActionToUnlock + mController.showActionToUnlock(); + + // THEN show 'swipe up to open' message + String swipeToOpen = mContext.getString(R.string.keyguard_unlock); + verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, swipeToOpen); } private void sendUpdateDisclosureBroadcast() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java index 4efd5c995a97..f42e6fb2d186 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java @@ -150,7 +150,6 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); when(mNotificationSwipeHelperBuilder.build()).thenReturn(mNotificationSwipeHelper); - when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false); mController = new NotificationStackScrollLayoutController( true, @@ -166,7 +165,6 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { mKeyguardMediaController, mKeyguardBypassController, mZenModeController, - mColorExtractor, mNotificationLockscreenUserManager, mMetricsLogger, mDumpManager, @@ -179,15 +177,12 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { mLegacyGroupManager, mLegacyGroupManager, mSilentHeaderController, - mNotifPipelineFlags, mNotifPipeline, mNotifCollection, mEntryManager, mLockscreenShadeTransitionController, mShadeTransitionController, - mIStatusBarService, mUiEventLogger, - mLayoutInflater, mRemoteInputManager, mVisualStabilityManager, mShadeController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java index 39021d8732d3..60a3d95e24f6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java @@ -230,6 +230,15 @@ public class KeyguardBouncerTest extends SysuiTestCase { } @Test + public void show_notifiesKeyguardViewController() { + mBouncer.ensureView(); + + mBouncer.show(/* resetSecuritySelection= */ false); + + verify(mKeyguardHostViewController).onBouncerVisibilityChanged(View.VISIBLE); + } + + @Test public void testHide_notifiesFalsingManager() { mBouncer.hide(false); verify(mFalsingCollector).onBouncerHidden(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java index d55875994468..98cd0804bfd2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java @@ -173,6 +173,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { @Mock private KeyguardBottomAreaView mKeyguardBottomArea; @Mock + private KeyguardBottomAreaViewController mKeyguardBottomAreaViewController; + @Mock private KeyguardBottomAreaView mQsFrame; private KeyguardStatusView mKeyguardStatusView; @Mock @@ -400,6 +402,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(1000); when(mNotificationStackScrollLayoutController.getHeadsUpCallback()) .thenReturn(mHeadsUpCallback); + when(mKeyguardBottomAreaViewController.getView()).thenReturn(mKeyguardBottomArea); when(mView.findViewById(R.id.keyguard_bottom_area)).thenReturn(mKeyguardBottomArea); when(mKeyguardBottomArea.animate()).thenReturn(mock(ViewPropertyAnimator.class)); when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame); @@ -482,7 +485,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { mMainHandler = new Handler(Looper.getMainLooper()); mPanelEventsEmitter = new NotificationPanelViewController.PanelEventsEmitter(); - mNotificationPanelViewController = new NotificationPanelViewController(mView, + mNotificationPanelViewController = new NotificationPanelViewController( + mView, mMainHandler, mLayoutInflater, mFeatureFlags, @@ -533,6 +537,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { mInteractionJankMonitor, mQsFrameTranslateController, mSysUiState, + () -> mKeyguardBottomAreaViewController, mKeyguardUnlockAnimationController, mNotificationListContainer, mPanelEventsEmitter, @@ -986,6 +991,21 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { } @Test + public void testSwipe_exactlyToTarget_notifiesNssl() { + // No over-expansion + mNotificationPanelViewController.setOverExpansion(0f); + // Fling to a target that is equal to the current position (i.e. a no-op fling). + mNotificationPanelViewController.flingToHeight( + 0f, + true, + mNotificationPanelViewController.mExpandedHeight, + 1f, + false); + // Verify that the NSSL is notified that the panel is *not* flinging. + verify(mNotificationStackScrollLayoutController).setPanelFlinging(false); + } + + @Test public void testDoubleTapRequired_Keyguard() { FalsingManager.FalsingTapListener listener = getFalsingTapListener(); mStatusBarStateController.setState(KEYGUARD); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 0c1d04253bf5..a6b0bc345742 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -389,6 +389,16 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { } @Test + public void testBouncerIsOrWillBeShowing_whenBouncerIsInTransit() { + when(mBouncer.isShowing()).thenReturn(false); + when(mBouncer.inTransit()).thenReturn(true); + + assertTrue( + "Is or will be showing should be true when bouncer is in transit", + mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()); + } + + @Test public void testShowAltAuth_unlockingWithBiometricNotAllowed() { // GIVEN alt auth exists, unlocking with biometric isn't allowed mStatusBarKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index ecea14c6a522..f53f5fb2aebd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -59,18 +59,15 @@ import com.android.systemui.assist.AssistManager; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationClickNotifier; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -127,8 +124,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { @Mock private ShadeControllerImpl mShadeController; @Mock - private NotifPipelineFlags mNotifPipelineFlags; - @Mock private NotifPipeline mNotifPipeline; @Mock private NotificationVisibilityProvider mVisibilityProvider; @@ -148,15 +143,13 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { private ActivityLaunchAnimator mActivityLaunchAnimator; @Mock private InteractionJankMonitor mJankMonitor; - private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); - private NotificationTestHelper mNotificationTestHelper; + private final FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); private ExpandableNotificationRow mNotificationRow; private ExpandableNotificationRow mBubbleNotificationRow; private final Answer<Void> mCallOnDismiss = answerVoid( (OnDismissAction dismissAction, Runnable cancel, Boolean afterKeyguardGone) -> dismissAction.onDismiss()); - private ArrayList<NotificationEntry> mActiveNotifications; @Before public void setUp() throws Exception { @@ -165,29 +158,28 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { when(mContentIntent.getCreatorUserHandle()).thenReturn(UserHandle.of(1)); when(mContentIntent.getIntent()).thenReturn(mContentIntentInner); - mNotificationTestHelper = new NotificationTestHelper( + NotificationTestHelper notificationTestHelper = new NotificationTestHelper( mContext, mDependency, TestableLooper.get(this)); // Create standard notification with contentIntent - mNotificationRow = mNotificationTestHelper.createRow(); + mNotificationRow = notificationTestHelper.createRow(); StatusBarNotification sbn = mNotificationRow.getEntry().getSbn(); sbn.getNotification().contentIntent = mContentIntent; sbn.getNotification().flags |= Notification.FLAG_AUTO_CANCEL; // Create bubble notification row with contentIntent - mBubbleNotificationRow = mNotificationTestHelper.createBubble(); + mBubbleNotificationRow = notificationTestHelper.createBubble(); StatusBarNotification bubbleSbn = mBubbleNotificationRow.getEntry().getSbn(); bubbleSbn.getNotification().contentIntent = mContentIntent; bubbleSbn.getNotification().flags |= Notification.FLAG_AUTO_CANCEL; - mActiveNotifications = new ArrayList<>(); - mActiveNotifications.add(mNotificationRow.getEntry()); - mActiveNotifications.add(mBubbleNotificationRow.getEntry()); - when(mEntryManager.getVisibleNotifications()).thenReturn(mActiveNotifications); + ArrayList<NotificationEntry> activeNotifications = new ArrayList<>(); + activeNotifications.add(mNotificationRow.getEntry()); + activeNotifications.add(mBubbleNotificationRow.getEntry()); + when(mEntryManager.getVisibleNotifications()).thenReturn(activeNotifications); when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); - when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false); when(mOnUserInteractionCallback.registerFutureDismissal(eq(mNotificationRow.getEntry()), anyInt())).thenReturn(mFutureDismissalRunnable); when(mVisibilityProvider.obtain(anyString(), anyBoolean())) @@ -207,23 +199,19 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mNotificationActivityStarter = new StatusBarNotificationActivityStarter( getContext(), - mock(CommandQueue.class), mHandler, mUiBgExecutor, - mEntryManager, mNotifPipeline, mVisibilityProvider, headsUpManager, mActivityStarter, mClickNotifier, - mock(StatusBarStateController.class), mStatusBarKeyguardViewManager, mock(KeyguardManager.class), mock(IDreamManager.class), Optional.of(mBubblesManager), () -> mAssistManager, mRemoteInputManager, - mock(NotificationGroupManagerLegacy.class), mock(NotificationLockscreenUserManager.class), mShadeController, mKeyguardStateController, @@ -231,7 +219,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mock(LockPatternUtils.class), mock(StatusBarRemoteInputCallback.class), mActivityIntentHelper, - mNotifPipelineFlags, mock(MetricsLogger.class), mock(StatusBarNotificationActivityStarterLogger.class), mOnUserInteractionCallback, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index 1a3dd3a7a2a5..0bfd1aed6b1e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -33,7 +33,6 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.testing.FakeMetricsLogger; -import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.ForegroundServiceNotificationListener; import com.android.systemui.InitController; import com.android.systemui.SysuiTestCase; @@ -50,7 +49,6 @@ import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotifPipelineFlags; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource; @@ -61,7 +59,6 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; -import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Before; @@ -125,15 +122,12 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { mock(NotificationLockscreenUserManager.class), mock(SysuiStatusBarStateController.class), mock(NotifShadeEventSource.class), - mock(NotificationEntryManager.class), mock(NotificationMediaManager.class), mock(NotificationGutsManager.class), - mock(KeyguardUpdateMonitor.class), lockscreenGestureLogger, mInitController, mNotificationInterruptStateProvider, mock(NotificationRemoteInputManager.class), - mock(ConfigurationController.class), mock(NotifPipelineFlags.class), mock(NotificationRemoteInputManager.Callback.class), mock(NotificationListContainer.class)); diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 8fe57e18ea37..bd1a2a61e830 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -123,6 +123,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.widget.IRemoteViewsFactory; import com.android.server.LocalServices; +import com.android.server.ServiceThread; import com.android.server.WidgetBackupProvider; import org.xmlpull.v1.XmlPullParser; @@ -266,7 +267,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku mDevicePolicyManagerInternal = LocalServices.getService(DevicePolicyManagerInternal.class); mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mSaveStateHandler = BackgroundThread.getHandler(); - mCallbackHandler = new CallbackHandler(mContext.getMainLooper()); + final ServiceThread serviceThread = new ServiceThread(TAG, + android.os.Process.THREAD_PRIORITY_FOREGROUND, false /* allowIo */); + serviceThread.start(); + mCallbackHandler = new CallbackHandler(serviceThread.getLooper()); mBackupRestoreController = new BackupRestoreController(); mSecurityPolicy = new SecurityPolicy(); mIsProviderInfoPersisted = !ActivityManager.isLowRamDeviceStatic() @@ -307,26 +311,26 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); packageFilter.addDataScheme("package"); mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, - packageFilter, null, null); + packageFilter, null, mCallbackHandler); // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, - sdFilter, null, null); + sdFilter, null, mCallbackHandler); IntentFilter offModeFilter = new IntentFilter(); offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, - offModeFilter, null, null); + offModeFilter, null, mCallbackHandler); IntentFilter suspendPackageFilter = new IntentFilter(); suspendPackageFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); suspendPackageFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, - suspendPackageFilter, null, null); + suspendPackageFilter, null, mCallbackHandler); } private void registerOnCrossProfileProvidersChangedListener() { diff --git a/services/companion/java/com/android/server/companion/PackageUtils.java b/services/companion/java/com/android/server/companion/PackageUtils.java index a2b20593a9cb..6b235879486c 100644 --- a/services/companion/java/com/android/server/companion/PackageUtils.java +++ b/services/companion/java/com/android/server/companion/PackageUtils.java @@ -30,6 +30,7 @@ import android.companion.CompanionDeviceService; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.FeatureInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.PackageInfoFlags; @@ -39,8 +40,6 @@ import android.content.pm.ServiceInfo; import android.os.Binder; import android.util.Slog; -import com.android.internal.util.ArrayUtils; - import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -65,15 +64,18 @@ final class PackageUtils { static void enforceUsesCompanionDeviceFeature(@NonNull Context context, @UserIdInt int userId, @NonNull String packageName) { - final boolean requested = ArrayUtils.contains( - getPackageInfo(context, userId, packageName).reqFeatures, - FEATURE_COMPANION_DEVICE_SETUP); - - if (requested) { - throw new IllegalStateException("Must declare uses-feature " - + FEATURE_COMPANION_DEVICE_SETUP - + " in manifest to use this API"); + String requiredFeature = FEATURE_COMPANION_DEVICE_SETUP; + + FeatureInfo[] requestedFeatures = getPackageInfo(context, userId, packageName).reqFeatures; + for (int i = 0; i < requestedFeatures.length; i++) { + if (requiredFeature.equals(requestedFeatures[i].name)) { + return; + } } + + throw new IllegalStateException("Must declare uses-feature " + + requiredFeature + + " in manifest to use this API"); } /** diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index c678a67e5bd3..e1a0bfd25c9f 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -160,6 +160,7 @@ public class Watchdog implements Dumpable { public static final String[] AIDL_INTERFACE_PREFIXES_OF_INTEREST = new String[] { "android.hardware.biometrics.face.IFace/", "android.hardware.biometrics.fingerprint.IFingerprint/", + "android.hardware.input.processor.IInputProcessor/", "android.hardware.light.ILights/", "android.hardware.power.IPower/", "android.hardware.power.stats.IPowerStats/", diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 92a8dcd2ba8f..98e3a214435a 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -2269,7 +2269,9 @@ public final class ProcessList { final boolean inBgRestricted = ast.isAppBackgroundRestricted( app.info.uid, app.info.packageName); if (inBgRestricted) { - mAppsInBackgroundRestricted.add(app); + synchronized (mService) { + mAppsInBackgroundRestricted.add(app); + } } app.mState.setBackgroundRestricted(inBgRestricted); } diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java index 1b669322e553..12324bff0c7a 100644 --- a/services/core/java/com/android/server/notification/PermissionHelper.java +++ b/services/core/java/com/android/server/notification/PermissionHelper.java @@ -17,6 +17,7 @@ package com.android.server.notification; import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; +import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.PERMISSION_GRANTED; @@ -176,9 +177,8 @@ public final class PermissionHelper { mPermManager.revokeRuntimePermission(packageName, NOTIFICATION_PERMISSION, userId, TAG); } - int flagMask = userSet || !grant - ? FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT : - FLAG_PERMISSION_USER_SET; + int flagMask = FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED; + flagMask = userSet || !grant ? flagMask | FLAG_PERMISSION_GRANTED_BY_DEFAULT : flagMask; if (userSet) { mPermManager.updatePermissionFlags(packageName, NOTIFICATION_PERMISSION, flagMask, FLAG_PERMISSION_USER_SET, true, userId); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 867be2427741..10bd4eef4f7e 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -308,7 +308,6 @@ import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; import android.util.proto.ProtoOutputStream; import android.view.AppTransitionAnimationSpec; -import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.InputApplicationHandle; @@ -352,6 +351,7 @@ import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.WindowManagerService.H; import com.android.server.wm.utils.InsetUtils; +import com.android.server.wm.utils.WmDisplayCutout; import dalvik.annotation.optimization.NeverCompile; @@ -9609,9 +9609,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); final int dw = rotated ? display.mBaseDisplayHeight : display.mBaseDisplayWidth; final int dh = rotated ? display.mBaseDisplayWidth : display.mBaseDisplayHeight; - final DisplayCutout cutout = display.calculateDisplayCutoutForRotation(rotation) - .getDisplayCutout(); - policy.getNonDecorInsetsLw(rotation, cutout, mNonDecorInsets[rotation]); + final WmDisplayCutout cutout = display.calculateDisplayCutoutForRotation(rotation); + policy.getNonDecorInsetsLw(rotation, dw, dh, cutout, mNonDecorInsets[rotation]); mStableInsets[rotation].set(mNonDecorInsets[rotation]); policy.convertNonDecorInsetsToStableInsets(mStableInsets[rotation], rotation); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index d5362a070d8e..890b91025151 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2565,7 +2565,6 @@ class ActivityStarter { mInTask = null; } mInTaskFragment = inTaskFragment; - sendNewTaskFragmentResultRequestIfNeeded(); mStartFlags = startFlags; // If the onlyIfNeeded flag is set, then we can do this if the activity being launched @@ -2608,18 +2607,6 @@ class ActivityStarter { } } - private void sendNewTaskFragmentResultRequestIfNeeded() { - if (mStartActivity.resultTo != null && mInTaskFragment != null - && mInTaskFragment != mStartActivity.resultTo.getTaskFragment()) { - Slog.w(TAG, - "Activity is launching as a new TaskFragment, so cancelling activity result."); - mStartActivity.resultTo.sendResult(INVALID_UID, mStartActivity.resultWho, - mStartActivity.requestCode, RESULT_CANCELED, - null /* data */, null /* dataGrants */); - mStartActivity.resultTo = null; - } - } - private void computeLaunchingTaskFlags() { // If the caller is not coming from another activity, but has given us an explicit task into // which they would like us to launch the new activity, then let's see about doing that. diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 124b8a654a78..bbc3558540d6 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -436,7 +436,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp */ final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics(); - /** @see #computeCompatSmallestWidth(boolean, int, int, int) */ + /** @see #computeCompatSmallestWidth(boolean, int, int) */ private final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics(); /** @@ -2012,7 +2012,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // the top of the method, the caller is obligated to call computeNewConfigurationLocked(). // By updating the Display info here it will be available to // #computeScreenConfiguration() later. - updateDisplayAndOrientation(getConfiguration().uiMode, null /* outConfig */); + updateDisplayAndOrientation(null /* outConfig */); // NOTE: We disable the rotation in the emulator because // it doesn't support hardware OpenGL emulation yet. @@ -2062,7 +2062,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * changed. * Do not call if {@link WindowManagerService#mDisplayReady} == false. */ - private DisplayInfo updateDisplayAndOrientation(int uiMode, Configuration outConfig) { + private DisplayInfo updateDisplayAndOrientation(Configuration outConfig) { // Use the effective "visual" dimensions based on current rotation final int rotation = getRotation(); final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); @@ -2074,18 +2074,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp final DisplayCutout displayCutout = wmDisplayCutout.getDisplayCutout(); final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation); - final int appWidth = mDisplayPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, - displayCutout); - final int appHeight = mDisplayPolicy.getNonDecorDisplayHeight(dh, rotation, - displayCutout); + final Rect appFrame = mDisplayPolicy.getNonDecorDisplayFrame(dw, dh, rotation, + wmDisplayCutout); mDisplayInfo.rotation = rotation; mDisplayInfo.logicalWidth = dw; mDisplayInfo.logicalHeight = dh; mDisplayInfo.logicalDensityDpi = mBaseDisplayDensity; mDisplayInfo.physicalXDpi = mBaseDisplayPhysicalXDpi; mDisplayInfo.physicalYDpi = mBaseDisplayPhysicalYDpi; - mDisplayInfo.appWidth = appWidth; - mDisplayInfo.appHeight = appHeight; + mDisplayInfo.appWidth = appFrame.width(); + mDisplayInfo.appHeight = appFrame.height(); if (isDefaultDisplay) { mDisplayInfo.getLogicalMetrics(mRealDisplayMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null); @@ -2099,7 +2097,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mDisplayInfo.flags &= ~Display.FLAG_SCALING_DISABLED; } - computeSizeRangesAndScreenLayout(mDisplayInfo, rotated, uiMode, dw, dh, + computeSizeRangesAndScreenLayout(mDisplayInfo, rotated, dw, dh, mDisplayMetrics.density, outConfig); mWmService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(mDisplayId, @@ -2189,10 +2187,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp outConfig.windowConfiguration.setMaxBounds(0, 0, dw, dh); outConfig.windowConfiguration.setBounds(outConfig.windowConfiguration.getMaxBounds()); - final int uiMode = getConfiguration().uiMode; - final DisplayCutout displayCutout = - calculateDisplayCutoutForRotation(rotation).getDisplayCutout(); - computeScreenAppConfiguration(outConfig, dw, dh, rotation, uiMode, displayCutout); + final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation); + computeScreenAppConfiguration(outConfig, dw, dh, rotation, wmDisplayCutout); final DisplayInfo displayInfo = new DisplayInfo(mDisplayInfo); displayInfo.rotation = rotation; @@ -2201,38 +2197,35 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp final Rect appBounds = outConfig.windowConfiguration.getAppBounds(); displayInfo.appWidth = appBounds.width(); displayInfo.appHeight = appBounds.height(); + final DisplayCutout displayCutout = wmDisplayCutout.getDisplayCutout(); displayInfo.displayCutout = displayCutout.isEmpty() ? null : displayCutout; - computeSizeRangesAndScreenLayout(displayInfo, rotated, uiMode, dw, dh, + computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, mDisplayMetrics.density, outConfig); return displayInfo; } /** Compute configuration related to application without changing current display. */ private void computeScreenAppConfiguration(Configuration outConfig, int dw, int dh, - int rotation, int uiMode, DisplayCutout displayCutout) { - final int appWidth = mDisplayPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, - displayCutout); - final int appHeight = mDisplayPolicy.getNonDecorDisplayHeight(dh, rotation, - displayCutout); - mDisplayPolicy.getNonDecorInsetsLw(rotation, displayCutout, mTmpRect); - final int leftInset = mTmpRect.left; - final int topInset = mTmpRect.top; + int rotation, WmDisplayCutout wmDisplayCutout) { + DisplayFrames displayFrames = + mDisplayPolicy.getSimulatedDisplayFrames(rotation, dw, dh, wmDisplayCutout); + final Rect appFrame = + mDisplayPolicy.getNonDecorDisplayFrameWithSimulatedFrame(displayFrames); // AppBounds at the root level should mirror the app screen size. - outConfig.windowConfiguration.setAppBounds(leftInset /* left */, topInset /* top */, - leftInset + appWidth /* right */, topInset + appHeight /* bottom */); + outConfig.windowConfiguration.setAppBounds(appFrame); outConfig.windowConfiguration.setRotation(rotation); outConfig.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; final float density = mDisplayMetrics.density; - outConfig.screenWidthDp = (int) (mDisplayPolicy.getConfigDisplayWidth(dw, dh, rotation, - uiMode, displayCutout) / density + 0.5f); - outConfig.screenHeightDp = (int) (mDisplayPolicy.getConfigDisplayHeight(dw, dh, rotation, - uiMode, displayCutout) / density + 0.5f); + final Point configSize = + mDisplayPolicy.getConfigDisplaySizeWithSimulatedFrame(displayFrames); + outConfig.screenWidthDp = (int) (configSize.x / density + 0.5f); + outConfig.screenHeightDp = (int) (configSize.y / density + 0.5f); outConfig.compatScreenWidthDp = (int) (outConfig.screenWidthDp / mCompatibleScreenScale); outConfig.compatScreenHeightDp = (int) (outConfig.screenHeightDp / mCompatibleScreenScale); final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); - outConfig.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, uiMode, dw, dh); + outConfig.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dw, dh); outConfig.windowConfiguration.setDisplayRotation(rotation); } @@ -2241,7 +2234,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * Do not call if mDisplayReady == false. */ void computeScreenConfiguration(Configuration config) { - final DisplayInfo displayInfo = updateDisplayAndOrientation(config.uiMode, config); + final DisplayInfo displayInfo = updateDisplayAndOrientation(config); final int dw = displayInfo.logicalWidth; final int dh = displayInfo.logicalHeight; mTmpRect.set(0, 0, dw, dh); @@ -2250,8 +2243,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp config.windowConfiguration.setWindowingMode(getWindowingMode()); config.windowConfiguration.setDisplayWindowingMode(getWindowingMode()); - computeScreenAppConfiguration(config, dw, dh, displayInfo.rotation, config.uiMode, - displayInfo.displayCutout); + computeScreenAppConfiguration(config, dw, dh, displayInfo.rotation, + calculateDisplayCutoutForRotation(getRotation())); config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK) | ((displayInfo.flags & Display.FLAG_ROUND) != 0 @@ -2340,7 +2333,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mWmService.mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence); } - private int computeCompatSmallestWidth(boolean rotated, int uiMode, int dw, int dh) { + private int computeCompatSmallestWidth(boolean rotated, int dw, int dh) { mTmpDisplayMetrics.setTo(mDisplayMetrics); final DisplayMetrics tmpDm = mTmpDisplayMetrics; final int unrotDw, unrotDh; @@ -2351,25 +2344,20 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp unrotDw = dw; unrotDh = dh; } - int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, - unrotDh); - sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, - unrotDw); - sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, - unrotDh); - sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, - unrotDw); + int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, tmpDm, unrotDw, unrotDh); + sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, tmpDm, unrotDh, unrotDw); + sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, tmpDm, unrotDw, unrotDh); + sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, tmpDm, unrotDh, unrotDw); return sw; } - private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode, + private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm, int dw, int dh) { - final DisplayCutout displayCutout = calculateDisplayCutoutForRotation( - rotation).getDisplayCutout(); - dm.noncompatWidthPixels = mDisplayPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, - displayCutout); - dm.noncompatHeightPixels = mDisplayPolicy.getNonDecorDisplayHeight(dh, rotation, - displayCutout); + final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation); + final Rect nonDecorSize = mDisplayPolicy.getNonDecorDisplayFrame(dw, dh, rotation, + wmDisplayCutout); + dm.noncompatWidthPixels = nonDecorSize.width(); + dm.noncompatHeightPixels = nonDecorSize.height(); float scale = CompatibilityInfo.computeCompatibleScaling(dm, null); int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f); if (curSize == 0 || size < curSize) { @@ -2379,7 +2367,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated, - int uiMode, int dw, int dh, float density, Configuration outConfig) { + int dw, int dh, float density, Configuration outConfig) { // We need to determine the smallest width that will occur under normal // operation. To this, start with the base screen size and compute the @@ -2397,37 +2385,34 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp displayInfo.smallestNominalAppHeight = 1<<30; displayInfo.largestNominalAppWidth = 0; displayInfo.largestNominalAppHeight = 0; - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, uiMode, unrotDw, unrotDh); - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, uiMode, unrotDh, unrotDw); - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, uiMode, unrotDw, unrotDh); - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, uiMode, unrotDh, unrotDw); + adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh); + adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw); + adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh); + adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw); if (outConfig == null) { return; } int sl = Configuration.resetScreenLayout(outConfig.screenLayout); - sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode); - sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode); - sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode); - sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode); + sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh); + sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw); + sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh); + sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw); outConfig.smallestScreenWidthDp = (int) (displayInfo.smallestNominalAppWidth / density + 0.5f); outConfig.screenLayout = sl; } - private int reduceConfigLayout(int curLayout, int rotation, float density, int dw, int dh, - int uiMode) { + private int reduceConfigLayout(int curLayout, int rotation, float density, int dw, int dh) { // Get the display cutout at this rotation. - final DisplayCutout displayCutout = calculateDisplayCutoutForRotation( - rotation).getDisplayCutout(); + final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation); // Get the app screen size at this rotation. - int w = mDisplayPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, displayCutout); - int h = mDisplayPolicy.getNonDecorDisplayHeight(dh, rotation, displayCutout); + final Rect size = mDisplayPolicy.getNonDecorDisplayFrame(dw, dh, rotation, wmDisplayCutout); // Compute the screen layout size class for this rotation. - int longSize = w; - int shortSize = h; + int longSize = size.width(); + int shortSize = size.height(); if (longSize < shortSize) { int tmp = longSize; longSize = shortSize; @@ -2438,25 +2423,20 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return Configuration.reduceScreenLayout(curLayout, longSize, shortSize); } - private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, - int uiMode, int dw, int dh) { - final DisplayCutout displayCutout = calculateDisplayCutoutForRotation( - rotation).getDisplayCutout(); - final int width = mDisplayPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode, - displayCutout); - if (width < displayInfo.smallestNominalAppWidth) { - displayInfo.smallestNominalAppWidth = width; + private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) { + final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation); + final Point size = mDisplayPolicy.getConfigDisplaySize(dw, dh, rotation, wmDisplayCutout); + if (size.x < displayInfo.smallestNominalAppWidth) { + displayInfo.smallestNominalAppWidth = size.x; } - if (width > displayInfo.largestNominalAppWidth) { - displayInfo.largestNominalAppWidth = width; + if (size.x > displayInfo.largestNominalAppWidth) { + displayInfo.largestNominalAppWidth = size.x; } - final int height = mDisplayPolicy.getConfigDisplayHeight(dw, dh, rotation, uiMode, - displayCutout); - if (height < displayInfo.smallestNominalAppHeight) { - displayInfo.smallestNominalAppHeight = height; + if (size.y < displayInfo.smallestNominalAppHeight) { + displayInfo.smallestNominalAppHeight = size.y; } - if (height > displayInfo.largestNominalAppHeight) { - displayInfo.largestNominalAppHeight = height; + if (size.y > displayInfo.largestNominalAppHeight) { + displayInfo.largestNominalAppHeight = size.y; } } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 98a51a97110d..337027947b2c 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -102,6 +102,7 @@ import android.content.Intent; import android.content.res.Resources; import android.graphics.Insets; import android.graphics.PixelFormat; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.gui.DropInputMode; @@ -126,6 +127,8 @@ import android.view.InsetsSource; import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; import android.view.InsetsVisibilities; +import android.view.PrivacyIndicatorBounds; +import android.view.RoundedCorners; import android.view.Surface; import android.view.View; import android.view.ViewDebug; @@ -159,6 +162,7 @@ import com.android.server.policy.WindowManagerPolicy.ScreenOnListener; import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wallpaper.WallpaperManagerInternal; +import com.android.server.wm.utils.WmDisplayCutout; import java.io.PrintWriter; import java.util.ArrayList; @@ -1990,35 +1994,6 @@ public class DisplayPolicy { return mUiContext; } - private int getNavigationBarWidth(int rotation, int uiMode, int position) { - if (mNavigationBar == null) { - return 0; - } - LayoutParams lp = mNavigationBar.mAttrs; - if (lp.paramsForRotation != null - && lp.paramsForRotation.length == 4 - && lp.paramsForRotation[rotation] != null) { - lp = lp.paramsForRotation[rotation]; - } - Insets providedInsetsSize = null; - if (lp.providedInsets != null) { - for (InsetsFrameProvider provider : lp.providedInsets) { - if (provider.type != ITYPE_NAVIGATION_BAR) { - continue; - } - providedInsetsSize = provider.insetsSize; - } - } - if (providedInsetsSize != null) { - if (position == NAV_BAR_LEFT) { - return providedInsetsSize.left; - } else if (position == NAV_BAR_RIGHT) { - return providedInsetsSize.right; - } - } - return lp.width; - } - void notifyDisplayReady() { mHandler.post(() -> { final int displayId = getDisplayId(); @@ -2035,45 +2010,24 @@ public class DisplayPolicy { } /** - * Return the display width available after excluding any screen - * decorations that could never be removed in Honeycomb. That is, system bar or - * button bar. + * Return the display frame available after excluding any screen decorations that could never be + * removed in Honeycomb. That is, system bar or button bar. + * + * @return display frame excluding all non-decor insets. */ - public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, - DisplayCutout displayCutout) { - int width = fullWidth; - if (hasNavigationBar()) { - final int navBarPosition = navigationBarPosition(rotation); - if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) { - width -= getNavigationBarWidth(rotation, uiMode, navBarPosition); - } - } - if (displayCutout != null) { - width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight(); - } - return width; + Rect getNonDecorDisplayFrame(int fullWidth, int fullHeight, int rotation, + WmDisplayCutout cutout) { + final DisplayFrames displayFrames = + getSimulatedDisplayFrames(rotation, fullWidth, fullHeight, cutout); + return getNonDecorDisplayFrameWithSimulatedFrame(displayFrames); } - @VisibleForTesting - int getNavigationBarHeight(int rotation) { - if (mNavigationBar == null) { - return 0; - } - LayoutParams lp = mNavigationBar.mAttrs.forRotation(rotation); - Insets providedInsetsSize = null; - if (lp.providedInsets != null) { - for (InsetsFrameProvider provider : lp.providedInsets) { - if (provider.type != ITYPE_NAVIGATION_BAR) { - continue; - } - providedInsetsSize = provider.insetsSize; - if (providedInsetsSize != null) { - return providedInsetsSize.bottom; - } - break; - } - } - return lp.height; + Rect getNonDecorDisplayFrameWithSimulatedFrame(DisplayFrames displayFrames) { + final Rect nonDecorInsets = + getInsets(displayFrames, Type.displayCutout() | Type.navigationBars()).toRect(); + final Rect displayFrame = new Rect(displayFrames.mInsetsState.getDisplayFrame()); + displayFrame.inset(nonDecorInsets); + return displayFrame; } /** @@ -2095,53 +2049,24 @@ public class DisplayPolicy { } /** - * Return the display height available after excluding any screen - * decorations that could never be removed in Honeycomb. That is, system bar or - * button bar. - */ - public int getNonDecorDisplayHeight(int fullHeight, int rotation, DisplayCutout displayCutout) { - int height = fullHeight; - final int navBarPosition = navigationBarPosition(rotation); - if (navBarPosition == NAV_BAR_BOTTOM) { - height -= getNavigationBarHeight(rotation); - } - if (displayCutout != null) { - height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom(); - } - return height; - } - - /** - * Return the available screen width that we should report for the + * Return the available screen size that we should report for the * configuration. This must be no larger than - * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller + * {@link #getNonDecorDisplayFrame(int, int, int, DisplayCutout)}; it may be smaller * than that to account for more transient decoration like a status bar. */ - public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, - DisplayCutout displayCutout) { - return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout); + public Point getConfigDisplaySize(int fullWidth, int fullHeight, int rotation, + WmDisplayCutout wmDisplayCutout) { + final DisplayFrames displayFrames = getSimulatedDisplayFrames(rotation, fullWidth, + fullHeight, wmDisplayCutout); + return getConfigDisplaySizeWithSimulatedFrame(displayFrames); } - /** - * Return the available screen height that we should report for the - * configuration. This must be no larger than - * {@link #getNonDecorDisplayHeight(int, int, DisplayCutout)}; it may be smaller - * than that to account for more transient decoration like a status bar. - */ - public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, - DisplayCutout displayCutout) { - // There is a separate status bar at the top of the display. We don't count that as part - // of the fixed decor, since it can hide; however, for purposes of configurations, - // we do want to exclude it since applications can't generally use that part - // of the screen. - int statusBarHeight = mStatusBarHeightForRotation[rotation]; - if (displayCutout != null) { - // If there is a cutout, it may already have accounted for some part of the status - // bar height. - statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop()); - } - return getNonDecorDisplayHeight(fullHeight, rotation, displayCutout) - - statusBarHeight; + Point getConfigDisplaySizeWithSimulatedFrame(DisplayFrames displayFrames) { + final Insets insets = getInsets(displayFrames, + Type.displayCutout() | Type.navigationBars() | Type.statusBars()); + Rect configFrame = new Rect(displayFrames.mInsetsState.getDisplayFrame()); + configFrame.inset(insets); + return new Point(configFrame.width(), configFrame.height()); } /** @@ -2173,48 +2098,69 @@ public class DisplayPolicy { * Calculates the stable insets without running a layout. * * @param displayRotation the current display rotation + * @param displayWidth full display width + * @param displayHeight full display height * @param displayCutout the current display cutout * @param outInsets the insets to return */ - public void getStableInsetsLw(int displayRotation, DisplayCutout displayCutout, - Rect outInsets) { - outInsets.setEmpty(); + public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight, + WmDisplayCutout displayCutout, Rect outInsets) { + final DisplayFrames displayFrames = getSimulatedDisplayFrames(displayRotation, + displayWidth, displayHeight, displayCutout); + getStableInsetsWithSimulatedFrame(displayFrames, outInsets); + } - // Navigation bar and status bar. - getNonDecorInsetsLw(displayRotation, displayCutout, outInsets); - convertNonDecorInsetsToStableInsets(outInsets, displayRotation); + void getStableInsetsWithSimulatedFrame(DisplayFrames displayFrames, Rect outInsets) { + // Navigation bar, status bar, and cutout. + outInsets.set(getInsets(displayFrames, + Type.displayCutout() | Type.navigationBars() | Type.statusBars()).toRect()); } /** * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system - * bar or button bar. See {@link #getNonDecorDisplayWidth}. - * @param displayRotation the current display rotation - * @param displayCutout the current display cutout + * bar or button bar. See {@link #getNonDecorDisplayFrame}. + * + * @param displayRotation the current display rotation + * @param fullWidth the width of the display, including all insets + * @param fullHeight the height of the display, including all insets + * @param cutout the current display cutout * @param outInsets the insets to return */ - public void getNonDecorInsetsLw(int displayRotation, DisplayCutout displayCutout, - Rect outInsets) { - outInsets.setEmpty(); - - // Only navigation bar - if (hasNavigationBar()) { - final int uiMode = mService.mPolicy.getUiMode(); - int position = navigationBarPosition(displayRotation); - if (position == NAV_BAR_BOTTOM) { - outInsets.bottom = getNavigationBarHeight(displayRotation); - } else if (position == NAV_BAR_RIGHT) { - outInsets.right = getNavigationBarWidth(displayRotation, uiMode, position); - } else if (position == NAV_BAR_LEFT) { - outInsets.left = getNavigationBarWidth(displayRotation, uiMode, position); - } - } + public void getNonDecorInsetsLw(int displayRotation, int fullWidth, int fullHeight, + WmDisplayCutout cutout, Rect outInsets) { + final DisplayFrames displayFrames = + getSimulatedDisplayFrames(displayRotation, fullWidth, fullHeight, cutout); + getNonDecorInsetsWithSimulatedFrame(displayFrames, outInsets); + } + + void getNonDecorInsetsWithSimulatedFrame(DisplayFrames displayFrames, Rect outInsets) { + outInsets.set(getInsets(displayFrames, + Type.displayCutout() | Type.navigationBars()).toRect()); + } + + DisplayFrames getSimulatedDisplayFrames(int displayRotation, int fullWidth, + int fullHeight, WmDisplayCutout cutout) { + final DisplayInfo info = new DisplayInfo(mDisplayContent.getDisplayInfo()); + info.rotation = displayRotation; + info.logicalWidth = fullWidth; + info.logicalHeight = fullHeight; + info.displayCutout = cutout.getDisplayCutout(); + final RoundedCorners roundedCorners = + mDisplayContent.calculateRoundedCornersForRotation(displayRotation); + final PrivacyIndicatorBounds indicatorBounds = + mDisplayContent.calculatePrivacyIndicatorBoundsForRotation(displayRotation); + final DisplayFrames displayFrames = new DisplayFrames(getDisplayId(), new InsetsState(), + info, cutout, roundedCorners, indicatorBounds); + simulateLayoutDisplay(displayFrames); + return displayFrames; + } - if (displayCutout != null) { - outInsets.left += displayCutout.getSafeInsetLeft(); - outInsets.top += displayCutout.getSafeInsetTop(); - outInsets.right += displayCutout.getSafeInsetRight(); - outInsets.bottom += displayCutout.getSafeInsetBottom(); - } + @VisibleForTesting + Insets getInsets(DisplayFrames displayFrames, @InsetsType int type) { + final InsetsState state = displayFrames.mInsetsState; + final Insets insets = state.calculateInsets(state.getDisplayFrame(), type, + true /* ignoreVisibility */); + return insets; } @NavigationBarPosition @@ -2240,7 +2186,7 @@ public class DisplayPolicy { * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM */ @NavigationBarPosition - public int getNavBarPosition() { + int getNavBarPosition() { return mNavigationBarPosition; } diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 21c5886f085b..b34a3ede889c 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -98,6 +98,7 @@ import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledPredicate; import com.android.server.am.HostingRecord; import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.wm.utils.WmDisplayCutout; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -2194,11 +2195,13 @@ class TaskFragment extends WindowContainer<WindowContainer> { mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy(); - policy.getNonDecorInsetsLw(displayInfo.rotation, - displayInfo.displayCutout, mTmpInsets); + final WmDisplayCutout cutout = + rootTask.mDisplayContent.calculateDisplayCutoutForRotation(displayInfo.rotation); + final DisplayFrames displayFrames = policy.getSimulatedDisplayFrames(displayInfo.rotation, + displayInfo.logicalWidth, displayInfo.logicalHeight, cutout); + policy.getNonDecorInsetsWithSimulatedFrame(displayFrames, mTmpInsets); intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets); - - policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation); + policy.getStableInsetsWithSimulatedFrame(displayFrames, mTmpInsets); intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets); } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 09f6110b517f..c455ac1dd370 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -533,9 +533,14 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe } // Need to update layers on involved displays since they were all paused while // the animation played. This puts the layers back into the correct order. - for (int i = displays.size() - 1; i >= 0; --i) { - if (displays.valueAt(i) == null) continue; - displays.valueAt(i).assignChildLayers(t); + mController.mBuildingFinishLayers = true; + try { + for (int i = displays.size() - 1; i >= 0; --i) { + if (displays.valueAt(i) == null) continue; + displays.valueAt(i).assignChildLayers(t); + } + } finally { + mController.mBuildingFinishLayers = false; } if (rootLeash.isValid()) { t.reparent(rootLeash, null); diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index dbc2c5fb0ce3..88572a937156 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -100,6 +100,14 @@ class TransitionController { // TODO(b/188595497): remove when not needed. final StatusBarManagerInternal mStatusBar; + /** + * `true` when building surface layer order for the finish transaction. We want to prevent + * wm from touching z-order of surfaces during transitions, but we still need to be able to + * calculate the layers for the finishTransaction. So, when assigning layers into the finish + * transaction, set this to true so that the {@link canAssignLayers} will allow it. + */ + boolean mBuildingFinishLayers = false; + TransitionController(ActivityTaskManagerService atm, TaskSnapshotController taskSnapshotController, TransitionTracer transitionTracer) { @@ -309,6 +317,15 @@ class TransitionController { return false; } + /** + * Whether WM can assign layers to window surfaces at this time. This is usually false while + * playing, but can be "opened-up" for certain transition operations like calculating layers + * for finishTransaction. + */ + boolean canAssignLayers() { + return mBuildingFinishLayers || !isPlaying(); + } + @WindowConfiguration.WindowingMode int getWindowingModeAtStart(@NonNull WindowContainer wc) { if (mCollectingTransition == null) return wc.getWindowingMode(); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 19b3384ee404..d9b25adb8c4c 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -429,6 +429,13 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (insetsTypes == null || insetsTypes.length == 0) { throw new IllegalArgumentException("Insets type not specified."); } + if (mDisplayContent == null) { + // This is possible this container is detached when WM shell is responding to a previous + // request. WM shell will be updated when this container is attached again and the + // insets need to be updated. + Slog.w(TAG, "Can't add local rect insets source provider when detached. " + this); + return; + } if (mLocalInsetsSourceProviders == null) { mLocalInsetsSourceProviders = new SparseArray<>(); } @@ -1011,6 +1018,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (dc != null && dc != this) { dc.getPendingTransaction().merge(mPendingTransaction); } + if (dc != this && mLocalInsetsSourceProviders != null) { + mLocalInsetsSourceProviders.clear(); + } for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowContainer child = mChildren.get(i); child.onDisplayChanged(dc); @@ -2473,7 +2483,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< void assignLayer(Transaction t, int layer) { // Don't assign layers while a transition animation is playing // TODO(b/173528115): establish robust best-practices around z-order fighting. - if (mTransitionController.isPlaying()) return; + if (!mTransitionController.canAssignLayers()) return; final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null; if (mSurfaceControl != null && changed) { setLayer(t, layer); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index d31dfeed389d..86876c327f7b 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -317,6 +317,7 @@ import com.android.server.policy.WindowManagerPolicy; import com.android.server.policy.WindowManagerPolicy.ScreenOffListener; import com.android.server.power.ShutdownThread; import com.android.server.utils.PriorityDump; +import com.android.server.wm.utils.WmDisplayCutout; import dalvik.annotation.optimization.NeverCompile; @@ -1853,7 +1854,8 @@ public class WindowManagerService extends IWindowManager.Stub ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s" + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5)); - if (win.isVisibleRequestedOrAdding() && displayContent.updateOrientation()) { + if ((win.isVisibleRequestedOrAdding() && displayContent.updateOrientation()) + || win.providesNonDecorInsets()) { displayContent.sendNewConfiguration(); } @@ -6376,7 +6378,8 @@ public class WindowManagerService extends IWindowManager.Stub + " callers=" + Debug.getCallers(3)); return NAV_BAR_INVALID; } - return displayContent.getDisplayPolicy().getNavBarPosition(); + return displayContent.getDisplayPolicy().navigationBarPosition( + displayContent.getDisplayRotation().getRotation()); } } @@ -7217,7 +7220,9 @@ public class WindowManagerService extends IWindowManager.Stub final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc != null) { final DisplayInfo di = dc.getDisplayInfo(); - dc.getDisplayPolicy().getStableInsetsLw(di.rotation, di.displayCutout, outInsets); + final WmDisplayCutout cutout = dc.calculateDisplayCutoutForRotation(di.rotation); + dc.getDisplayPolicy().getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, + cutout, outInsets); } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index af8c4c8e9370..b3fe19f41233 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -244,6 +244,7 @@ import android.view.View; import android.view.ViewDebug; import android.view.ViewTreeObserver; import android.view.WindowInfo; +import android.view.WindowInsets; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowManager; import android.view.animation.Animation; @@ -1921,6 +1922,19 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return (mPolicyVisibility & POLICY_VISIBILITY_ALL) == POLICY_VISIBILITY_ALL; } + boolean providesNonDecorInsets() { + if (mProvidedInsetsSources == null) { + return false; + } + for (int i = mProvidedInsetsSources.size() - 1; i >= 0; i--) { + final int type = mProvidedInsetsSources.keyAt(i); + if ((InsetsState.toPublicType(type) & WindowInsets.Type.navigationBars()) != 0) { + return true; + } + } + return false; + } + void clearPolicyVisibilityFlag(int policyVisibilityFlag) { mPolicyVisibility &= ~policyVisibilityFlag; mWmService.scheduleAnimationLocked(); @@ -2631,14 +2645,19 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } removeImmediately(); - // Removing a visible window will effect the computed orientation - // So just update orientation if needed. + boolean sentNewConfig = false; if (wasVisible) { + // Removing a visible window will effect the computed orientation + // So just update orientation if needed. final DisplayContent displayContent = getDisplayContent(); if (displayContent.updateOrientation()) { displayContent.sendNewConfiguration(); + sentNewConfig = true; } } + if (!sentNewConfig && providesNonDecorInsets()) { + getDisplayContent().sendNewConfiguration(); + } mWmService.updateFocusedWindowLocked(isFocused() ? UPDATE_FOCUS_REMOVING_FOCUS : UPDATE_FOCUS_NORMAL, diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java index d4886e440c41..f2b1dc9132d5 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java @@ -18,6 +18,7 @@ package com.android.server.notification; import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; +import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.PERMISSION_DENIED; @@ -74,6 +75,8 @@ public class PermissionHelperTest extends UiServiceTestCase { private PermissionHelper mPermissionHelper; + private static final int USER_FLAG_MASK = FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_USER_FIXED; + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -183,7 +186,7 @@ public class PermissionHelperTest extends UiServiceTestCase { verify(mPermManager).grantRuntimePermission( "pkg", Manifest.permission.POST_NOTIFICATIONS, 10); verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS, - FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT, + USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT, FLAG_PERMISSION_USER_SET, true, 10); } @@ -202,7 +205,7 @@ public class PermissionHelperTest extends UiServiceTestCase { verify(mPermManager).grantRuntimePermission( "pkg", Manifest.permission.POST_NOTIFICATIONS, 10); verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS, - FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT, + USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT, FLAG_PERMISSION_USER_SET, true, 10); } @@ -216,7 +219,7 @@ public class PermissionHelperTest extends UiServiceTestCase { verify(mPermManager).revokeRuntimePermission( eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString()); verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS, - FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT, + USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT, FLAG_PERMISSION_USER_SET, true, 10); } @@ -230,7 +233,7 @@ public class PermissionHelperTest extends UiServiceTestCase { verify(mPermManager).grantRuntimePermission( "pkg", Manifest.permission.POST_NOTIFICATIONS, 10); verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS, - FLAG_PERMISSION_USER_SET, 0, true, 10); + USER_FLAG_MASK, 0, true, 10); } @Test @@ -243,7 +246,7 @@ public class PermissionHelperTest extends UiServiceTestCase { verify(mPermManager).revokeRuntimePermission( eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString()); verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS, - FLAG_PERMISSION_USER_SET | FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, + USER_FLAG_MASK | FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, true, 10); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 3f3d01a14f80..ea0e8c91c930 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -157,6 +157,7 @@ import androidx.test.filters.MediumTest; import com.android.internal.R; import com.android.server.wm.ActivityRecord.State; +import com.android.server.wm.utils.WmDisplayCutout; import org.junit.Assert; import org.junit.Before; @@ -550,7 +551,8 @@ public class ActivityRecordTests extends WindowTestsBase { final Rect insets = new Rect(); final DisplayInfo displayInfo = task.mDisplayContent.getDisplayInfo(); final DisplayPolicy policy = task.mDisplayContent.getDisplayPolicy(); - policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.displayCutout, insets); + policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth, + displayInfo.logicalHeight, WmDisplayCutout.NO_CUTOUT, insets); policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation); Task.intersectWithInsetsIfFits(stableRect, stableRect, insets); @@ -591,7 +593,8 @@ public class ActivityRecordTests extends WindowTestsBase { final Rect insets = new Rect(); final DisplayInfo displayInfo = rootTask.mDisplayContent.getDisplayInfo(); final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy(); - policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.displayCutout, insets); + policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth, + displayInfo.logicalHeight, WmDisplayCutout.NO_CUTOUT, insets); policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation); Task.intersectWithInsetsIfFits(stableRect, stableRect, insets); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java index f41fee789bf2..a001eda2f86e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java @@ -25,10 +25,13 @@ import static org.hamcrest.Matchers.equalTo; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; +import android.util.Pair; import android.view.DisplayInfo; import androidx.test.filters.SmallTest; +import com.android.server.wm.utils.WmDisplayCutout; + import org.junit.Rule; import org.junit.Test; import org.junit.rules.ErrorCollector; @@ -46,7 +49,8 @@ public class DisplayPolicyInsetsTests extends DisplayPolicyTestsBase { @Test public void portrait() { - final DisplayInfo di = displayInfoForRotation(ROTATION_0, false /* withCutout */); + final Pair<DisplayInfo, WmDisplayCutout> di = + displayInfoForRotation(ROTATION_0, false /* withCutout */); verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT); @@ -55,7 +59,8 @@ public class DisplayPolicyInsetsTests extends DisplayPolicyTestsBase { @Test public void portrait_withCutout() { - final DisplayInfo di = displayInfoForRotation(ROTATION_0, true /* withCutout */); + final Pair<DisplayInfo, WmDisplayCutout> di = + displayInfoForRotation(ROTATION_0, true /* withCutout */); verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); verifyNonDecorInsets(di, 0, DISPLAY_CUTOUT_HEIGHT, 0, NAV_BAR_HEIGHT); @@ -64,7 +69,8 @@ public class DisplayPolicyInsetsTests extends DisplayPolicyTestsBase { @Test public void landscape() { - final DisplayInfo di = displayInfoForRotation(ROTATION_90, false /* withCutout */); + final Pair<DisplayInfo, WmDisplayCutout> di = + displayInfoForRotation(ROTATION_90, false /* withCutout */); if (mDisplayPolicy.navigationBarCanMove()) { verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0); @@ -79,7 +85,8 @@ public class DisplayPolicyInsetsTests extends DisplayPolicyTestsBase { @Test public void landscape_withCutout() { - final DisplayInfo di = displayInfoForRotation(ROTATION_90, true /* withCutout */); + final Pair<DisplayInfo, WmDisplayCutout> di = + displayInfoForRotation(ROTATION_90, true /* withCutout */); if (mDisplayPolicy.navigationBarCanMove()) { verifyStableInsets(di, DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0); @@ -94,7 +101,8 @@ public class DisplayPolicyInsetsTests extends DisplayPolicyTestsBase { @Test public void seascape() { - final DisplayInfo di = displayInfoForRotation(ROTATION_270, false /* withCutout */); + final Pair<DisplayInfo, WmDisplayCutout> di = + displayInfoForRotation(ROTATION_270, false /* withCutout */); if (mDisplayPolicy.navigationBarCanMove()) { verifyStableInsets(di, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0); @@ -109,7 +117,8 @@ public class DisplayPolicyInsetsTests extends DisplayPolicyTestsBase { @Test public void seascape_withCutout() { - final DisplayInfo di = displayInfoForRotation(ROTATION_270, true /* withCutout */); + final Pair<DisplayInfo, WmDisplayCutout> di = + displayInfoForRotation(ROTATION_270, true /* withCutout */); if (mDisplayPolicy.navigationBarCanMove()) { verifyStableInsets(di, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0); @@ -124,7 +133,8 @@ public class DisplayPolicyInsetsTests extends DisplayPolicyTestsBase { @Test public void upsideDown() { - final DisplayInfo di = displayInfoForRotation(ROTATION_180, false /* withCutout */); + final Pair<DisplayInfo, WmDisplayCutout> di = + displayInfoForRotation(ROTATION_180, false /* withCutout */); verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT); @@ -133,28 +143,34 @@ public class DisplayPolicyInsetsTests extends DisplayPolicyTestsBase { @Test public void upsideDown_withCutout() { - final DisplayInfo di = displayInfoForRotation(ROTATION_180, true /* withCutout */); + final Pair<DisplayInfo, WmDisplayCutout> di = + displayInfoForRotation(ROTATION_180, true /* withCutout */); verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT + DISPLAY_CUTOUT_HEIGHT); verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT + DISPLAY_CUTOUT_HEIGHT); verifyConsistency(di); } - private void verifyStableInsets(DisplayInfo di, int left, int top, int right, int bottom) { - mErrorCollector.checkThat("stableInsets", getStableInsetsLw(di), equalTo(new Rect( - left, top, right, bottom))); + private void verifyStableInsets(Pair<DisplayInfo, WmDisplayCutout> diPair, int left, int top, + int right, int bottom) { + mErrorCollector.checkThat("stableInsets", getStableInsetsLw(diPair.first, diPair.second), + equalTo(new Rect(left, top, right, bottom))); } - private void verifyNonDecorInsets(DisplayInfo di, int left, int top, int right, int bottom) { - mErrorCollector.checkThat("nonDecorInsets", getNonDecorInsetsLw(di), equalTo(new Rect( + private void verifyNonDecorInsets(Pair<DisplayInfo, WmDisplayCutout> diPair, int left, int top, + int right, int bottom) { + mErrorCollector.checkThat("nonDecorInsets", + getNonDecorInsetsLw(diPair.first, diPair.second), equalTo(new Rect( left, top, right, bottom))); } - private void verifyConsistency(DisplayInfo di) { - verifyConsistency("configDisplay", di, getStableInsetsLw(di), - getConfigDisplayWidth(di), getConfigDisplayHeight(di)); - verifyConsistency("nonDecorDisplay", di, getNonDecorInsetsLw(di), - getNonDecorDisplayWidth(di), getNonDecorDisplayHeight(di)); + private void verifyConsistency(Pair<DisplayInfo, WmDisplayCutout> diPair) { + final DisplayInfo di = diPair.first; + final WmDisplayCutout cutout = diPair.second; + verifyConsistency("configDisplay", di, getStableInsetsLw(di, cutout), + getConfigDisplayWidth(di, cutout), getConfigDisplayHeight(di, cutout)); + verifyConsistency("nonDecorDisplay", di, getNonDecorInsetsLw(di, cutout), + getNonDecorDisplayWidth(di, cutout), getNonDecorDisplayHeight(di, cutout)); } private void verifyConsistency(String what, DisplayInfo di, Rect insets, int width, @@ -165,39 +181,42 @@ public class DisplayPolicyInsetsTests extends DisplayPolicyTestsBase { equalTo(di.logicalHeight - insets.top - insets.bottom)); } - private Rect getStableInsetsLw(DisplayInfo di) { + private Rect getStableInsetsLw(DisplayInfo di, WmDisplayCutout cutout) { Rect result = new Rect(); - mDisplayPolicy.getStableInsetsLw(di.rotation, di.displayCutout, result); + mDisplayPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, + cutout, result); return result; } - private Rect getNonDecorInsetsLw(DisplayInfo di) { + private Rect getNonDecorInsetsLw(DisplayInfo di, WmDisplayCutout cutout) { Rect result = new Rect(); - mDisplayPolicy.getNonDecorInsetsLw(di.rotation, di.displayCutout, result); + mDisplayPolicy.getNonDecorInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, + cutout, result); return result; } - private int getNonDecorDisplayWidth(DisplayInfo di) { - return mDisplayPolicy.getNonDecorDisplayWidth(di.logicalWidth, di.logicalHeight, - di.rotation, 0 /* ui */, di.displayCutout); + private int getNonDecorDisplayWidth(DisplayInfo di, WmDisplayCutout cutout) { + return mDisplayPolicy.getNonDecorDisplayFrame(di.logicalWidth, di.logicalHeight, + di.rotation, cutout).width(); } - private int getNonDecorDisplayHeight(DisplayInfo di) { - return mDisplayPolicy.getNonDecorDisplayHeight(di.logicalHeight, di.rotation, - di.displayCutout); + private int getNonDecorDisplayHeight(DisplayInfo di, WmDisplayCutout cutout) { + return mDisplayPolicy.getNonDecorDisplayFrame(di.logicalWidth, di.logicalHeight, + di.rotation, cutout).height(); } - private int getConfigDisplayWidth(DisplayInfo di) { - return mDisplayPolicy.getConfigDisplayWidth(di.logicalWidth, di.logicalHeight, - di.rotation, 0 /* ui */, di.displayCutout); + private int getConfigDisplayWidth(DisplayInfo di, WmDisplayCutout cutout) { + return mDisplayPolicy.getConfigDisplaySize(di.logicalWidth, di.logicalHeight, + di.rotation, cutout).x; } - private int getConfigDisplayHeight(DisplayInfo di) { - return mDisplayPolicy.getConfigDisplayHeight(di.logicalWidth, di.logicalHeight, - di.rotation, 0 /* ui */, di.displayCutout); + private int getConfigDisplayHeight(DisplayInfo di, WmDisplayCutout cutout) { + return mDisplayPolicy.getConfigDisplaySize(di.logicalWidth, di.logicalHeight, + di.rotation, cutout).y; } - private static DisplayInfo displayInfoForRotation(int rotation, boolean withDisplayCutout) { - return displayInfoAndCutoutForRotation(rotation, withDisplayCutout, false).first; + private static Pair<DisplayInfo, WmDisplayCutout> displayInfoForRotation(int rotation, + boolean withDisplayCutout) { + return displayInfoAndCutoutForRotation(rotation, withDisplayCutout, false); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java index 1e64e469fe7f..e0de76f95fee 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java @@ -26,12 +26,9 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doReturn; - import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; @@ -43,6 +40,7 @@ import android.util.DisplayMetrics; import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayInfo; +import android.view.WindowInsets; import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry; @@ -204,7 +202,11 @@ class TestDisplayContent extends DisplayContent { doReturn(true).when(newDisplay).supportsSystemDecorations(); doReturn(true).when(displayPolicy).hasNavigationBar(); doReturn(NAV_BAR_BOTTOM).when(displayPolicy).navigationBarPosition(anyInt()); - doReturn(20).when(displayPolicy).getNavigationBarHeight(anyInt()); + doReturn(Insets.of(0, 0, 0, 20)).when(displayPolicy).getInsets(any(), + eq(WindowInsets.Type.displayCutout() | WindowInsets.Type.navigationBars())); + doReturn(Insets.of(0, 20, 0, 20)).when(displayPolicy).getInsets(any(), + eq(WindowInsets.Type.displayCutout() | WindowInsets.Type.navigationBars() + | WindowInsets.Type.statusBars())); } else { doReturn(false).when(displayPolicy).hasNavigationBar(); doReturn(false).when(displayPolicy).hasStatusBar(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 8a539cd3ddff..919418bde821 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -323,6 +323,10 @@ class WindowTestsBase extends SystemServiceTestsBase { mNavBarWindow.mAttrs.gravity = Gravity.BOTTOM; mNavBarWindow.mAttrs.paramsForRotation = new WindowManager.LayoutParams[4]; mNavBarWindow.mAttrs.setFitInsetsTypes(0); + mNavBarWindow.mAttrs.layoutInDisplayCutoutMode = + LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; + mNavBarWindow.mAttrs.privateFlags |= + WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT; for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) { mNavBarWindow.mAttrs.paramsForRotation[rot] = getNavBarLayoutParamsForRotation(rot); @@ -379,6 +383,9 @@ class WindowTestsBase extends SystemServiceTestsBase { lp.height = height; lp.gravity = gravity; lp.setFitInsetsTypes(0); + lp.privateFlags |= + WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT; + lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; return lp; } |