summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java4
-rw-r--r--core/java/android/app/ActivityThread.java26
-rw-r--r--core/java/android/app/ActivityThreadInternal.java2
-rw-r--r--core/java/android/app/ConfigurationController.java10
-rw-r--r--core/java/android/app/ContextImpl.java4
-rw-r--r--core/java/android/app/Notification.java1
-rw-r--r--core/java/android/content/pm/ActivityInfo.java8
-rw-r--r--core/java/android/content/pm/ConstrainDisplayApisConfig.java164
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java11
-rw-r--r--core/java/android/os/AppZygote.java8
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java11
-rw-r--r--core/java/android/util/ArrayMap.java2
-rw-r--r--core/java/android/view/translation/UiTranslationController.java5
-rw-r--r--core/java/android/widget/RemoteViews.java11
-rw-r--r--core/java/android/widget/TextViewTranslationCallback.java11
-rw-r--r--core/java/android/window/PictureInPictureSurfaceTransaction.java118
-rw-r--r--core/java/android/window/WindowTokenClient.java10
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java45
-rw-r--r--core/proto/android/server/windowmanagerservice.proto1
-rw-r--r--core/res/res/layout/chooser_grid.xml2
-rw-r--r--core/res/res/layout/chooser_grid_preview_image.xml4
-rw-r--r--core/res/res/values-sw600dp/config.xml2
-rw-r--r--core/res/res/values-sw600dp/dimens.xml3
-rw-r--r--core/res/res/values/config.xml2
-rw-r--r--core/res/res/values/dimens.xml5
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java24
-rw-r--r--data/etc/platform.xml1
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java5
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java24
-rw-r--r--libs/WindowManager/Shell/res/drawable/compat_hint_bubble.xml (renamed from libs/WindowManager/Shell/res/drawable/size_compat_hint_bubble.xml)4
-rw-r--r--libs/WindowManager/Shell/res/drawable/compat_hint_point.xml (renamed from libs/WindowManager/Shell/res/drawable/size_compat_hint_point.xml)4
-rw-r--r--libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml6
-rw-r--r--libs/WindowManager/Shell/res/layout/compat_mode_hint.xml46
-rw-r--r--libs/WindowManager/Shell/res/layout/compat_ui_layout.xml (renamed from libs/WindowManager/Shell/res/layout/size_compat_ui.xml)11
-rw-r--r--libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml58
-rw-r--r--libs/WindowManager/Shell/res/values/colors.xml6
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java56
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUI.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUI.java)8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java)79
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java89
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java321
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopup.java66
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java76
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java344
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java127
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java20
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java32
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java (renamed from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java)48
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java (renamed from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java)58
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java253
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java85
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java284
-rw-r--r--packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java10
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java13
-rw-r--r--packages/SystemUI/res-keyguard/drawable/ic_unlocked_aod.xml44
-rw-r--r--packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml20
-rw-r--r--packages/SystemUI/res-keyguard/drawable/unlocked_aod_to_ls.xml133
-rw-r--r--packages/SystemUI/res-keyguard/drawable/unlocked_ls_to_aod.xml136
-rw-r--r--packages/SystemUI/res-keyguard/drawable/unlocked_to_aod_lock.xml169
-rw-r--r--packages/SystemUI/res/drawable/internet_dialog_footer_background.xml30
-rw-r--r--packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml2
-rw-r--r--packages/SystemUI/res/drawable/screenrecord_button_background_outline.xml30
-rw-r--r--packages/SystemUI/res/layout/auth_biometric_contents.xml3
-rw-r--r--packages/SystemUI/res/layout/auth_credential_password_view.xml107
-rw-r--r--packages/SystemUI/res/layout/auth_credential_pattern_view.xml125
-rw-r--r--packages/SystemUI/res/layout/internet_connectivity_dialog.xml43
-rw-r--r--packages/SystemUI/res/layout/media_output_dialog.xml12
-rw-r--r--packages/SystemUI/res/layout/screen_record_dialog.xml18
-rw-r--r--packages/SystemUI/res/layout/status_bar_no_notifications.xml3
-rw-r--r--packages/SystemUI/res/values-h800dp/dimens.xml2
-rw-r--r--packages/SystemUI/res/values-night/colors.xml2
-rw-r--r--packages/SystemUI/res/values/colors.xml8
-rw-r--r--packages/SystemUI/res/values/config.xml11
-rw-r--r--packages/SystemUI/res/values/dimens.xml2
-rw-r--r--packages/SystemUI/res/values/styles.xml53
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java26
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java18
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java62
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java64
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/UserUtil.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt145
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java95
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogManager.java118
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt71
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java10
-rw-r--r--services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java17
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java4
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java10
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java65
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java8
-rw-r--r--services/core/java/com/android/server/camera/CameraServiceProxy.java98
-rw-r--r--services/core/java/com/android/server/location/provider/LocationProviderManager.java63
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java25
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java14
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java44
-rw-r--r--services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java9
-rw-r--r--services/core/java/com/android/server/wm/LockTaskController.java48
-rw-r--r--services/core/java/com/android/server/wm/PinnedTaskController.java20
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java10
-rw-r--r--services/core/java/com/android/server/wm/Task.java56
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowContextListenerController.java41
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java10
-rw-r--r--services/people/java/com/android/server/people/data/ConversationStatusExpirationBroadcastReceiver.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java31
-rw-r--r--services/tests/servicestests/AndroidTest.xml7
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ServiceRestarterTest.java88
-rw-r--r--services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml1
-rw-r--r--services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleService.java20
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java73
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java1
174 files changed, 3318 insertions, 2271 deletions
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 806283229d98..7e382870b016 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -518,7 +518,9 @@ public abstract class AccessibilityService extends Service {
public static final int GLOBAL_ACTION_POWER_DIALOG = 6;
/**
- * Action to toggle docking the current app's window
+ * Action to toggle docking the current app's window.
+ * <p>
+ * <strong>Note:</strong> It is effective only if it appears in {@link #getSystemActions()}.
*/
public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 45df0d9a8a9f..46f6597bb042 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -321,7 +321,8 @@ public final class ActivityThread extends ClientTransactionHandler
@UnsupportedAppUsage
private ContextImpl mSystemContext;
- private final SparseArray<ContextImpl> mDisplaySystemUiContexts = new SparseArray<>();
+ @GuardedBy("this")
+ private SparseArray<ContextImpl> mDisplaySystemUiContexts;
@UnsupportedAppUsage
static volatile IPackageManager sPackageManager;
@@ -2650,7 +2651,6 @@ public final class ActivityThread extends ClientTransactionHandler
}
}
- @Override
@NonNull
public ContextImpl getSystemUiContext() {
return getSystemUiContext(DEFAULT_DISPLAY);
@@ -2664,6 +2664,9 @@ public final class ActivityThread extends ClientTransactionHandler
@NonNull
public ContextImpl getSystemUiContext(int displayId) {
synchronized (this) {
+ if (mDisplaySystemUiContexts == null) {
+ mDisplaySystemUiContexts = new SparseArray<>();
+ }
ContextImpl systemUiContext = mDisplaySystemUiContexts.get(displayId);
if (systemUiContext == null) {
systemUiContext = ContextImpl.createSystemUiContext(getSystemContext(), displayId);
@@ -2673,6 +2676,25 @@ public final class ActivityThread extends ClientTransactionHandler
}
}
+ @Nullable
+ @Override
+ public ContextImpl getSystemUiContextNoCreate() {
+ synchronized (this) {
+ if (mDisplaySystemUiContexts == null) return null;
+ return mDisplaySystemUiContexts.get(DEFAULT_DISPLAY);
+ }
+ }
+
+ void onSystemUiContextCleanup(ContextImpl context) {
+ synchronized (this) {
+ if (mDisplaySystemUiContexts == null) return;
+ final int index = mDisplaySystemUiContexts.indexOfValue(context);
+ if (index >= 0) {
+ mDisplaySystemUiContexts.removeAt(index);
+ }
+ }
+ }
+
public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
synchronized (this) {
getSystemContext().installSystemApplicationInfo(info, classLoader);
diff --git a/core/java/android/app/ActivityThreadInternal.java b/core/java/android/app/ActivityThreadInternal.java
index bc698f657305..b9ad5c337813 100644
--- a/core/java/android/app/ActivityThreadInternal.java
+++ b/core/java/android/app/ActivityThreadInternal.java
@@ -28,7 +28,7 @@ import java.util.ArrayList;
interface ActivityThreadInternal {
ContextImpl getSystemContext();
- ContextImpl getSystemUiContext();
+ ContextImpl getSystemUiContextNoCreate();
boolean isInDensityCompatMode();
diff --git a/core/java/android/app/ConfigurationController.java b/core/java/android/app/ConfigurationController.java
index 8637e31eb122..58f60a6a59a7 100644
--- a/core/java/android/app/ConfigurationController.java
+++ b/core/java/android/app/ConfigurationController.java
@@ -154,9 +154,12 @@ class ConfigurationController {
int configDiff;
boolean equivalent;
+ // Get theme outside of synchronization to avoid nested lock.
+ final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme();
+ final ContextImpl systemUiContext = mActivityThread.getSystemUiContextNoCreate();
+ final Resources.Theme systemUiTheme =
+ systemUiContext != null ? systemUiContext.getTheme() : null;
synchronized (mResourcesManager) {
- final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme();
- final Resources.Theme systemUiTheme = mActivityThread.getSystemUiContext().getTheme();
if (mPendingConfiguration != null) {
if (!mPendingConfiguration.isOtherSeqNewer(config)) {
config = mPendingConfiguration;
@@ -207,7 +210,8 @@ class ConfigurationController {
systemTheme.rebase();
}
- if ((systemUiTheme.getChangingConfigurations() & configDiff) != 0) {
+ if (systemUiTheme != null
+ && (systemUiTheme.getChangingConfigurations() & configDiff) != 0) {
systemUiTheme.rebase();
}
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index db3c7d9bcb02..fc1884a41653 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -3191,6 +3191,10 @@ class ContextImpl extends Context {
final void performFinalCleanup(String who, String what) {
//Log.i(TAG, "Cleanup up context: " + this);
mPackageInfo.removeContextRegistrations(getOuterContext(), who, what);
+ if (mContextType == CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI
+ && mToken instanceof WindowTokenClient) {
+ mMainThread.onSystemUiContextCleanup(this);
+ }
}
@UnsupportedAppUsage
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9605cbdb48c6..2c02be7dc6b9 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5810,6 +5810,7 @@ public class Notification implements Parcelable
p, result);
buildCustomContentIntoTemplate(mContext, standard, customContent,
p, result);
+ makeHeaderExpanded(standard);
return standard;
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 8daf9f0450c4..d1ef5917ba47 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1367,18 +1367,18 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
* Returns if the activity should never be sandboxed to the activity window bounds.
* @hide
*/
- public boolean neverSandboxDisplayApis() {
+ public boolean neverSandboxDisplayApis(ConstrainDisplayApisConfig constrainDisplayApisConfig) {
return isChangeEnabled(NEVER_SANDBOX_DISPLAY_APIS)
- || ConstrainDisplayApisConfig.neverConstrainDisplayApis(applicationInfo);
+ || constrainDisplayApisConfig.getNeverConstrainDisplayApis(applicationInfo);
}
/**
* Returns if the activity should always be sandboxed to the activity window bounds.
* @hide
*/
- public boolean alwaysSandboxDisplayApis() {
+ public boolean alwaysSandboxDisplayApis(ConstrainDisplayApisConfig constrainDisplayApisConfig) {
return isChangeEnabled(ALWAYS_SANDBOX_DISPLAY_APIS)
- || ConstrainDisplayApisConfig.alwaysConstrainDisplayApis(applicationInfo);
+ || constrainDisplayApisConfig.getAlwaysConstrainDisplayApis(applicationInfo);
}
/** @hide */
diff --git a/core/java/android/content/pm/ConstrainDisplayApisConfig.java b/core/java/android/content/pm/ConstrainDisplayApisConfig.java
index 11ba3d4ba9a2..98b73aa8860a 100644
--- a/core/java/android/content/pm/ConstrainDisplayApisConfig.java
+++ b/core/java/android/content/pm/ConstrainDisplayApisConfig.java
@@ -19,10 +19,15 @@ package android.content.pm;
import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS;
import android.provider.DeviceConfig;
+import android.util.ArrayMap;
+import android.util.Pair;
import android.util.Slog;
+import com.android.internal.os.BackgroundThread;
+
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
/**
* Class for processing flags in the Device Config namespace 'constrain_display_apis'.
@@ -55,19 +60,45 @@ public final class ConstrainDisplayApisConfig {
"always_constrain_display_apis";
/**
+ * Indicates that display APIs should never be constrained to the activity window bounds for all
+ * packages.
+ */
+ private boolean mNeverConstrainDisplayApisAllPackages;
+
+ /**
+ * Indicates that display APIs should never be constrained to the activity window bounds for
+ * a set of defined packages. Map keys are package names, and entries are a
+ * 'Pair(<min-version-code>, <max-version-code>)'.
+ */
+ private ArrayMap<String, Pair<Long, Long>> mNeverConstrainConfigMap;
+
+ /**
+ * Indicates that display APIs should always be constrained to the activity window bounds for
+ * a set of defined packages. Map keys are package names, and entries are a
+ * 'Pair(<min-version-code>, <max-version-code>)'.
+ */
+ private ArrayMap<String, Pair<Long, Long>> mAlwaysConstrainConfigMap;
+
+ public ConstrainDisplayApisConfig() {
+ updateCache();
+
+ DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_CONSTRAIN_DISPLAY_APIS,
+ BackgroundThread.getExecutor(), properties -> updateCache());
+ }
+
+ /**
* Returns true if either the flag 'never_constrain_display_apis_all_packages' is true or the
* flag 'never_constrain_display_apis' contains a package entry that matches the given {@code
* applicationInfo}.
*
* @param applicationInfo Information about the application/package.
*/
- public static boolean neverConstrainDisplayApis(ApplicationInfo applicationInfo) {
- if (DeviceConfig.getBoolean(NAMESPACE_CONSTRAIN_DISPLAY_APIS,
- FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES, /* defaultValue= */ false)) {
+ public boolean getNeverConstrainDisplayApis(ApplicationInfo applicationInfo) {
+ if (mNeverConstrainDisplayApisAllPackages) {
return true;
}
- return flagHasMatchingPackageEntry(FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, applicationInfo);
+ return flagHasMatchingPackageEntry(mNeverConstrainConfigMap, applicationInfo);
}
/**
@@ -76,73 +107,106 @@ public final class ConstrainDisplayApisConfig {
*
* @param applicationInfo Information about the application/package.
*/
- public static boolean alwaysConstrainDisplayApis(ApplicationInfo applicationInfo) {
- return flagHasMatchingPackageEntry(FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS, applicationInfo);
+ public boolean getAlwaysConstrainDisplayApis(ApplicationInfo applicationInfo) {
+ return flagHasMatchingPackageEntry(mAlwaysConstrainConfigMap, applicationInfo);
}
+
/**
- * Returns true if the flag with the given {@code flagName} contains a package entry that
- * matches the given {@code applicationInfo}.
- *
- * @param applicationInfo Information about the application/package.
+ * Updates {@link #mNeverConstrainDisplayApisAllPackages}, {@link #mNeverConstrainConfigMap},
+ * and {@link #mAlwaysConstrainConfigMap} from the {@link DeviceConfig}.
*/
- private static boolean flagHasMatchingPackageEntry(String flagName,
- ApplicationInfo applicationInfo) {
- String configStr = DeviceConfig.getString(NAMESPACE_CONSTRAIN_DISPLAY_APIS,
- flagName, /* defaultValue= */ "");
+ private void updateCache() {
+ mNeverConstrainDisplayApisAllPackages = DeviceConfig.getBoolean(
+ NAMESPACE_CONSTRAIN_DISPLAY_APIS,
+ FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES, /* defaultValue= */ false);
+
+ final String neverConstrainConfigStr = DeviceConfig.getString(
+ NAMESPACE_CONSTRAIN_DISPLAY_APIS,
+ FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, /* defaultValue= */ "");
+ mNeverConstrainConfigMap = buildConfigMap(neverConstrainConfigStr);
+
+ final String alwaysConstrainConfigStr = DeviceConfig.getString(
+ NAMESPACE_CONSTRAIN_DISPLAY_APIS,
+ FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS, /* defaultValue= */ "");
+ mAlwaysConstrainConfigMap = buildConfigMap(alwaysConstrainConfigStr);
+ }
+ /**
+ * Processes the configuration string into a map of version codes, for the given
+ * configuration to be applied to the specified packages. If the given package
+ * entry string is invalid, then the map will not contain an entry for the package.
+ *
+ * @param configStr A configuration string expected to be in the format of a list of package
+ * entries separated by ','. A package entry expected to be in the format
+ * '<package-name>:<min-version-code>?:<max-version-code>?'.
+ * @return a map of configuration entries, where each key is a package name. Each value is
+ * a pair of version codes, in the format 'Pair(<min-version-code>, <max-version-code>)'.
+ */
+ private static ArrayMap<String, Pair<Long, Long>> buildConfigMap(String configStr) {
+ ArrayMap<String, Pair<Long, Long>> configMap = new ArrayMap<>();
// String#split returns a non-empty array given an empty string.
if (configStr.isEmpty()) {
- return false;
+ return configMap;
}
-
for (String packageEntryString : configStr.split(",")) {
- if (matchesApplicationInfo(packageEntryString, applicationInfo)) {
- return true;
+ List<String> packageAndVersions = Arrays.asList(packageEntryString.split(":", 3));
+ if (packageAndVersions.size() != 3) {
+ Slog.w(TAG, "Invalid package entry in flag 'never/always_constrain_display_apis': "
+ + packageEntryString);
+ // Skip this entry.
+ continue;
+ }
+ String packageName = packageAndVersions.get(0);
+ String minVersionCodeStr = packageAndVersions.get(1);
+ String maxVersionCodeStr = packageAndVersions.get(2);
+ try {
+ final long minVersion =
+ minVersionCodeStr.isEmpty() ? Long.MIN_VALUE : Long.parseLong(
+ minVersionCodeStr);
+ final long maxVersion =
+ maxVersionCodeStr.isEmpty() ? Long.MAX_VALUE : Long.parseLong(
+ maxVersionCodeStr);
+ Pair<Long, Long> minMaxVersionCodes = new Pair<>(minVersion, maxVersion);
+ configMap.put(packageName, minMaxVersionCodes);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Invalid APK version code in package entry: " + packageEntryString);
+ // Skip this entry.
}
}
-
- return false;
+ return configMap;
}
/**
- * Parses the given {@code packageEntryString} and returns true if {@code
- * applicationInfo.packageName} matches the package name in the config and {@code
- * applicationInfo.longVersionCode} is within the version range in the config.
- *
- * <p>Logs a warning and returns false in case the given {@code packageEntryString} is invalid.
+ * Returns true if the flag with the given {@code flagName} contains a package entry that
+ * matches the given {@code applicationInfo}.
*
- * @param packageEntryStr A package entry expected to be in the format
- * '<package-name>:<min-version-code>?:<max-version-code>?'.
+ * @param configMap the map representing the current configuration value to examine
* @param applicationInfo Information about the application/package.
*/
- private static boolean matchesApplicationInfo(String packageEntryStr,
+ private static boolean flagHasMatchingPackageEntry(Map<String, Pair<Long, Long>> configMap,
ApplicationInfo applicationInfo) {
- List<String> packageAndVersions = Arrays.asList(packageEntryStr.split(":", 3));
- if (packageAndVersions.size() != 3) {
- Slog.w(TAG, "Invalid package entry in flag 'never_constrain_display_apis': "
- + packageEntryStr);
+ if (configMap.isEmpty()) {
return false;
}
- String packageName = packageAndVersions.get(0);
- String minVersionCodeStr = packageAndVersions.get(1);
- String maxVersionCodeStr = packageAndVersions.get(2);
-
- if (!packageName.equals(applicationInfo.packageName)) {
+ if (!configMap.containsKey(applicationInfo.packageName)) {
return false;
}
- long version = applicationInfo.longVersionCode;
- try {
- if (!minVersionCodeStr.isEmpty() && version < Long.parseLong(minVersionCodeStr)) {
- return false;
- }
- if (!maxVersionCodeStr.isEmpty() && version > Long.parseLong(maxVersionCodeStr)) {
- return false;
- }
- } catch (NumberFormatException e) {
- Slog.w(TAG, "Invalid APK version code in package entry: " + packageEntryStr);
- return false;
- }
- return true;
+ return matchesApplicationInfo(configMap.get(applicationInfo.packageName), applicationInfo);
+ }
+
+ /**
+ * Parses the given {@code minMaxVersionCodes} and returns true if {@code
+ * applicationInfo.longVersionCode} is within the version range in the pair.
+ * Returns false otherwise.
+ *
+ * @param minMaxVersionCodes A pair expected to be in the format
+ * 'Pair(<min-version-code>, <max-version-code>)'.
+ * @param applicationInfo Information about the application/package.
+ */
+ private static boolean matchesApplicationInfo(Pair<Long, Long> minMaxVersionCodes,
+ ApplicationInfo applicationInfo) {
+ return applicationInfo.longVersionCode >= minMaxVersionCodes.first
+ && applicationInfo.longVersionCode <= minMaxVersionCodes.second;
}
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 9f77a7e72e70..0b02a919b2d9 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2632,7 +2632,8 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* </tbody>
* </table>
* <p>For applications targeting SDK version 31 or newer, if the mobile device declares to be
- * {@link android.os.Build.VERSION_CDOES.MEDIA_PERFORMANCE_CLASS media performance class} S,
+ * media performance class 12 or higher by setting
+ * {@link android.os.Build.VERSION_CDOES.MEDIA_PERFORMANCE_CLASS } to be 31 or larger,
* the primary camera devices (first rear/front camera in the camera ID list) will not
* support JPEG sizes smaller than 1080p. If the application configures a JPEG stream
* smaller than 1080p, the camera device will round up the JPEG image size to at least
@@ -2705,9 +2706,11 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* </tbody>
* </table>
* <p>For applications targeting SDK version 31 or newer, if the mobile device doesn't declare
- * to be media performance class S, or if the camera device isn't a primary rear/front
- * camera, the minimum required output stream configurations are the same as for applications
- * targeting SDK version older than 31.</p>
+ * to be media performance class 12 or better by setting
+ * {@link android.os.Build.VERSION_CDOES.MEDIA_PERFORMANCE_CLASS } to be 31 or larger,
+ * or if the camera device isn't a primary rear/front camera, the minimum required output
+ * stream configurations are the same as for applications targeting SDK version older than
+ * 31.</p>
* <p>Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} for additional
* mandatory stream configurations on a per-capability basis.</p>
* <p>Exception on 176x144 (QCIF) resolution: camera devices usually have a fixed capability for
diff --git a/core/java/android/os/AppZygote.java b/core/java/android/os/AppZygote.java
index 74b814ea4159..c8b4226ecae0 100644
--- a/core/java/android/os/AppZygote.java
+++ b/core/java/android/os/AppZygote.java
@@ -45,6 +45,8 @@ public class AppZygote {
// Last UID/GID of the range the AppZygote can setuid()/setgid() to
private final int mZygoteUidGidMax;
+ private final int mZygoteRuntimeFlags;
+
private final Object mLock = new Object();
/**
@@ -56,11 +58,13 @@ public class AppZygote {
private final ApplicationInfo mAppInfo;
- public AppZygote(ApplicationInfo appInfo, int zygoteUid, int uidGidMin, int uidGidMax) {
+ public AppZygote(ApplicationInfo appInfo, int zygoteUid, int uidGidMin, int uidGidMax,
+ int runtimeFlags) {
mAppInfo = appInfo;
mZygoteUid = zygoteUid;
mZygoteUidGidMin = uidGidMin;
mZygoteUidGidMax = uidGidMax;
+ mZygoteRuntimeFlags = runtimeFlags;
}
/**
@@ -110,7 +114,7 @@ public class AppZygote {
mZygoteUid,
mZygoteUid,
null, // gids
- 0, // runtimeFlags
+ mZygoteRuntimeFlags, // runtimeFlags
"app_zygote", // seInfo
abi, // abi
abi, // acceptedAbiList
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 4d0fc1642874..ee32ce43821c 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1750,8 +1750,9 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
/**
* Called when there has been a failure transferring the {@link AssistStructure} to
* the assistant. This may happen, for example, if the data is too large and results
- * in an out of memory exception, or the client has provided corrupt data. This will
- * be called immediately before {@link #onHandleAssist} and the AssistStructure supplied
+ * in an out of memory exception, the data has been cleared during transferring due to
+ * the new incoming assist data, or the client has provided corrupt data. This will be
+ * called immediately before {@link #onHandleAssist} and the AssistStructure supplied
* there afterwards will be null.
*
* @param failure The failure exception that was thrown when building the
@@ -1789,7 +1790,8 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
* Called to receive data from the application that the user was currently viewing when
* an assist session is started. If the original show request did not specify
* {@link #SHOW_WITH_ASSIST}, {@link AssistState} parameter will only provide
- * {@link ActivityId}.
+ * {@link ActivityId}. If there was a failure to write the assist data to
+ * {@link AssistStructure}, the {@link AssistState#getAssistStructure()} will return null.
*
* <p>This method is called for all activities along with an index and count that indicates
* which activity the data is for. {@code index} will be between 0 and {@code count}-1 and
@@ -2214,7 +2216,8 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
* @return If available, the structure definition of all windows currently
* displayed by the app. May be null if assist data has been disabled by the user
* or device policy; will be null if the original show request did not specify
- * {@link #SHOW_WITH_ASSIST}; will be an empty stub if the application has disabled assist
+ * {@link #SHOW_WITH_ASSIST} or the assist data has been corrupt when writing the data to
+ * {@link AssistStructure}; will be an empty stub if the application has disabled assist
* by marking its window as secure.
*/
public @Nullable AssistStructure getAssistStructure() {
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index 4edff27d0ced..0b50192bfa48 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -646,7 +646,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {
e.fillInStackTrace();
Log.w(TAG, "New hash " + hash
+ " is before end of array hash " + mHashes[index-1]
- + " at index " + index + " key " + key, e);
+ + " at index " + index + (DEBUG ? " key " + key : ""), e);
put(key, value);
return;
}
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index 9d1bf171128e..fb534c7885e4 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -435,7 +435,10 @@ public class UiTranslationController {
if (view.getViewTranslationResponse() != null
&& view.getViewTranslationResponse().equals(response)) {
if (callback instanceof TextViewTranslationCallback) {
- if (((TextViewTranslationCallback) callback).isShowingTranslation()) {
+ TextViewTranslationCallback textViewCallback =
+ (TextViewTranslationCallback) callback;
+ if (textViewCallback.isShowingTranslation()
+ || textViewCallback.isAnimationRunning()) {
if (DEBUG) {
Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId
+ ". Ignoring.");
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 3d4d9eca6b16..dfd853acaf0d 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -3696,18 +3696,21 @@ public class RemoteViews implements Parcelable, Filter {
}
private void initializeFrom(@NonNull RemoteViews src, @Nullable RemoteViews hierarchyRoot) {
+ if (hierarchyRoot == null) {
+ mBitmapCache = src.mBitmapCache;
+ mApplicationInfoCache = src.mApplicationInfoCache;
+ } else {
+ mBitmapCache = hierarchyRoot.mBitmapCache;
+ mApplicationInfoCache = hierarchyRoot.mApplicationInfoCache;
+ }
if (hierarchyRoot == null || src.mIsRoot) {
// If there's no provided root, or if src was itself a root, then this RemoteViews is
// the root of the new hierarchy.
mIsRoot = true;
- mBitmapCache = new BitmapCache();
- mApplicationInfoCache = new ApplicationInfoCache();
hierarchyRoot = this;
} else {
// Otherwise, we're a descendant in the hierarchy.
mIsRoot = false;
- mBitmapCache = hierarchyRoot.mBitmapCache;
- mApplicationInfoCache = hierarchyRoot.mApplicationInfoCache;
}
mApplication = src.mApplication;
mLayoutId = src.mLayoutId;
diff --git a/core/java/android/widget/TextViewTranslationCallback.java b/core/java/android/widget/TextViewTranslationCallback.java
index 4a78f3ee6fac..942be21b1ade 100644
--- a/core/java/android/widget/TextViewTranslationCallback.java
+++ b/core/java/android/widget/TextViewTranslationCallback.java
@@ -46,6 +46,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
private TranslationTransformationMethod mTranslationTransformation;
private boolean mIsShowingTranslation = false;
+ private boolean mAnimationRunning = false;
private boolean mIsTextPaddingEnabled = false;
private CharSequence mPaddedText;
private int mAnimationDurationMillis = 250; // default value
@@ -92,6 +93,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
(TextView) view,
() -> {
mIsShowingTranslation = true;
+ mAnimationRunning = false;
// TODO(b/178353965): well-handle setTransformationMethod.
((TextView) view).setTransformationMethod(transformation);
});
@@ -124,6 +126,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
(TextView) view,
() -> {
mIsShowingTranslation = false;
+ mAnimationRunning = false;
((TextView) view).setTransformationMethod(transformation);
});
if (!TextUtils.isEmpty(mContentDescription)) {
@@ -162,6 +165,13 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
return mIsShowingTranslation;
}
+ /**
+ * Returns whether the view is running animation to show or hide the translation.
+ */
+ public boolean isAnimationRunning() {
+ return mAnimationRunning;
+ }
+
@Override
public void enableContentPadding() {
mIsTextPaddingEnabled = true;
@@ -230,6 +240,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
mAnimator.end();
// Note: mAnimator is now null; do not use again here.
}
+ mAnimationRunning = true;
int fadedOutColor = colorWithAlpha(view.getCurrentTextColor(), 0);
mAnimator = ValueAnimator.ofArgb(view.getCurrentTextColor(), fadedOutColor);
mAnimator.addUpdateListener(
diff --git a/core/java/android/window/PictureInPictureSurfaceTransaction.java b/core/java/android/window/PictureInPictureSurfaceTransaction.java
index dbf7eb34e273..2bf2f3193789 100644
--- a/core/java/android/window/PictureInPictureSurfaceTransaction.java
+++ b/core/java/android/window/PictureInPictureSurfaceTransaction.java
@@ -19,6 +19,7 @@ package android.window;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Matrix;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
@@ -34,9 +35,10 @@ import java.util.Objects;
* @hide
*/
public final class PictureInPictureSurfaceTransaction implements Parcelable {
+ private static final float NOT_SET = -1f;
- public final float mPositionX;
- public final float mPositionY;
+ public final float mAlpha;
+ public final PointF mPosition;
public final float[] mFloat9;
@@ -45,33 +47,37 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
public final float mCornerRadius;
- private final Rect mWindowCrop = new Rect();
+ private final Rect mWindowCrop;
- public PictureInPictureSurfaceTransaction(Parcel in) {
- mPositionX = in.readFloat();
- mPositionY = in.readFloat();
+ private PictureInPictureSurfaceTransaction(Parcel in) {
+ mAlpha = in.readFloat();
+ mPosition = in.readTypedObject(PointF.CREATOR);
mFloat9 = new float[9];
in.readFloatArray(mFloat9);
mRotation = in.readFloat();
mCornerRadius = in.readFloat();
- mWindowCrop.set(Objects.requireNonNull(in.readTypedObject(Rect.CREATOR)));
+ mWindowCrop = in.readTypedObject(Rect.CREATOR);
}
- public PictureInPictureSurfaceTransaction(float positionX, float positionY,
- float[] float9, float rotation, float cornerRadius,
+ private PictureInPictureSurfaceTransaction(float alpha, @Nullable PointF position,
+ @Nullable float[] float9, float rotation, float cornerRadius,
@Nullable Rect windowCrop) {
- mPositionX = positionX;
- mPositionY = positionY;
- mFloat9 = Arrays.copyOf(float9, 9);
- mRotation = rotation;
- mCornerRadius = cornerRadius;
- if (windowCrop != null) {
- mWindowCrop.set(windowCrop);
+ mAlpha = alpha;
+ mPosition = position;
+ if (float9 == null) {
+ mFloat9 = new float[9];
+ Matrix.IDENTITY_MATRIX.getValues(mFloat9);
+ mRotation = 0;
+ } else {
+ mFloat9 = Arrays.copyOf(float9, 9);
+ mRotation = rotation;
}
+ mCornerRadius = cornerRadius;
+ mWindowCrop = (windowCrop == null) ? null : new Rect(windowCrop);
}
public PictureInPictureSurfaceTransaction(PictureInPictureSurfaceTransaction other) {
- this(other.mPositionX, other.mPositionY,
+ this(other.mAlpha, other.mPosition,
other.mFloat9, other.mRotation, other.mCornerRadius, other.mWindowCrop);
}
@@ -82,13 +88,18 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
return matrix;
}
+ /** @return {@code true} if this transaction contains setting corner radius. */
+ public boolean hasCornerRadiusSet() {
+ return mCornerRadius > 0;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PictureInPictureSurfaceTransaction)) return false;
PictureInPictureSurfaceTransaction that = (PictureInPictureSurfaceTransaction) o;
- return Objects.equals(mPositionX, that.mPositionX)
- && Objects.equals(mPositionY, that.mPositionY)
+ return Objects.equals(mAlpha, that.mAlpha)
+ && Objects.equals(mPosition, that.mPosition)
&& Arrays.equals(mFloat9, that.mFloat9)
&& Objects.equals(mRotation, that.mRotation)
&& Objects.equals(mCornerRadius, that.mCornerRadius)
@@ -97,7 +108,7 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mPositionX, mPositionY, Arrays.hashCode(mFloat9),
+ return Objects.hash(mAlpha, mPosition, Arrays.hashCode(mFloat9),
mRotation, mCornerRadius, mWindowCrop);
}
@@ -108,8 +119,8 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeFloat(mPositionX);
- out.writeFloat(mPositionY);
+ out.writeFloat(mAlpha);
+ out.writeTypedObject(mPosition, 0 /* flags */);
out.writeFloatArray(mFloat9);
out.writeFloat(mRotation);
out.writeFloat(mCornerRadius);
@@ -120,8 +131,8 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
public String toString() {
final Matrix matrix = getMatrix();
return "PictureInPictureSurfaceTransaction("
- + " posX=" + mPositionX
- + " posY=" + mPositionY
+ + " alpha=" + mAlpha
+ + " position=" + mPosition
+ " matrix=" + matrix.toShortString()
+ " rotation=" + mRotation
+ " cornerRadius=" + mCornerRadius
@@ -134,11 +145,20 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
@NonNull SurfaceControl surfaceControl,
@NonNull SurfaceControl.Transaction tx) {
final Matrix matrix = surfaceTransaction.getMatrix();
- tx.setMatrix(surfaceControl, matrix, new float[9])
- .setPosition(surfaceControl,
- surfaceTransaction.mPositionX, surfaceTransaction.mPositionY)
- .setWindowCrop(surfaceControl, surfaceTransaction.mWindowCrop)
- .setCornerRadius(surfaceControl, surfaceTransaction.mCornerRadius);
+ tx.setMatrix(surfaceControl, matrix, new float[9]);
+ if (surfaceTransaction.mPosition != null) {
+ tx.setPosition(surfaceControl,
+ surfaceTransaction.mPosition.x, surfaceTransaction.mPosition.y);
+ }
+ if (surfaceTransaction.mWindowCrop != null) {
+ tx.setWindowCrop(surfaceControl, surfaceTransaction.mWindowCrop);
+ }
+ if (surfaceTransaction.hasCornerRadiusSet()) {
+ tx.setCornerRadius(surfaceControl, surfaceTransaction.mCornerRadius);
+ }
+ if (surfaceTransaction.mAlpha != NOT_SET) {
+ tx.setAlpha(surfaceControl, surfaceTransaction.mAlpha);
+ }
}
public static final @android.annotation.NonNull Creator<PictureInPictureSurfaceTransaction>
@@ -151,4 +171,44 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
return new PictureInPictureSurfaceTransaction[size];
}
};
+
+ public static class Builder {
+ private float mAlpha = NOT_SET;
+ private PointF mPosition;
+ private float[] mFloat9;
+ private float mRotation;
+ private float mCornerRadius = NOT_SET;
+ private Rect mWindowCrop;
+
+ public Builder setAlpha(float alpha) {
+ mAlpha = alpha;
+ return this;
+ }
+
+ public Builder setPosition(float x, float y) {
+ mPosition = new PointF(x, y);
+ return this;
+ }
+
+ public Builder setTransform(@NonNull float[] float9, float rotation) {
+ mFloat9 = Arrays.copyOf(float9, 9);
+ mRotation = rotation;
+ return this;
+ }
+
+ public Builder setCornerRadius(float cornerRadius) {
+ mCornerRadius = cornerRadius;
+ return this;
+ }
+
+ public Builder setWindowCrop(@NonNull Rect windowCrop) {
+ mWindowCrop = new Rect(windowCrop);
+ return this;
+ }
+
+ public PictureInPictureSurfaceTransaction build() {
+ return new PictureInPictureSurfaceTransaction(mAlpha, mPosition,
+ mFloat9, mRotation, mCornerRadius, mWindowCrop);
+ }
+ }
}
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index b331a9e81e27..4ba7ef26e9cb 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -15,7 +15,6 @@
*/
package android.window;
-import static android.window.ConfigurationHelper.diffPublicWithSizeBuckets;
import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;
import static android.window.ConfigurationHelper.isDifferentDisplay;
import static android.window.ConfigurationHelper.shouldUpdateResources;
@@ -222,14 +221,7 @@ public class WindowTokenClient extends IWindowToken.Stub {
() -> windowContext.dispatchConfigurationChanged(newConfig));
}
- // Dispatch onConfigurationChanged only if there's a significant public change to
- // make it compatible with the original behavior.
- final Configuration[] sizeConfigurations = context.getResources()
- .getSizeConfigurations();
- final SizeConfigurationBuckets buckets = sizeConfigurations != null
- ? new SizeConfigurationBuckets(sizeConfigurations) : null;
- final int diff = diffPublicWithSizeBuckets(mConfiguration, newConfig, buckets);
-
+ final int diff = mConfiguration.diffPublicOnly(newConfig);
if (shouldReportConfigChange && diff != 0
&& context instanceof WindowProviderService) {
final WindowProviderService windowProviderService = (WindowProviderService) context;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 786af5f0823e..7bb1ed8abc0a 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -163,9 +163,6 @@ public class ChooserActivity extends ResolverActivity implements
private AppPredictor mWorkAppPredictor;
private boolean mShouldDisplayLandscape;
- private static final int MAX_TARGETS_PER_ROW_PORTRAIT = 4;
- private static final int MAX_TARGETS_PER_ROW_LANDSCAPE = 8;
-
@UnsupportedAppUsage
public ChooserActivity() {
}
@@ -275,6 +272,7 @@ public class ChooserActivity extends ResolverActivity implements
private int mCurrAvailableWidth = 0;
private int mLastNumberOfChildren = -1;
+ private int mMaxTargetsPerRow = 1;
private static final String TARGET_DETAILS_FRAGMENT_TAG = "targetDetailsFragment";
@@ -741,8 +739,9 @@ public class ChooserActivity extends ResolverActivity implements
mCallerChooserTargets = targets;
}
- mShouldDisplayLandscape = shouldDisplayLandscape(
- getResources().getConfiguration().orientation);
+ mMaxTargetsPerRow = getResources().getInteger(R.integer.config_chooser_max_targets_per_row);
+ mShouldDisplayLandscape =
+ shouldDisplayLandscape(getResources().getConfiguration().orientation);
setRetainInOnStop(intent.getBooleanExtra(EXTRA_PRIVATE_RETAIN_IN_ON_STOP, false));
super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
null, false);
@@ -916,7 +915,7 @@ public class ChooserActivity extends ResolverActivity implements
adapter,
getPersonalProfileUserHandle(),
/* workProfileUserHandle= */ null,
- isSendAction(getTargetIntent()), getMaxTargetsPerRow());
+ isSendAction(getTargetIntent()), mMaxTargetsPerRow);
}
private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForTwoProfiles(
@@ -945,7 +944,7 @@ public class ChooserActivity extends ResolverActivity implements
selectedProfile,
getPersonalProfileUserHandle(),
getWorkProfileUserHandle(),
- isSendAction(getTargetIntent()), getMaxTargetsPerRow());
+ isSendAction(getTargetIntent()), mMaxTargetsPerRow);
}
private int findSelectedProfile() {
@@ -1107,6 +1106,7 @@ public class ChooserActivity extends ResolverActivity implements
}
mShouldDisplayLandscape = shouldDisplayLandscape(newConfig.orientation);
+ mMaxTargetsPerRow = getResources().getInteger(R.integer.config_chooser_max_targets_per_row);
adjustPreviewWidth(newConfig.orientation, null);
updateStickyContentPreview();
}
@@ -2690,7 +2690,7 @@ public class ChooserActivity extends ResolverActivity implements
// and b/150936654
recyclerView.setAdapter(gridAdapter);
((GridLayoutManager) recyclerView.getLayoutManager()).setSpanCount(
- getMaxTargetsPerRow());
+ mMaxTargetsPerRow);
}
UserHandle currentUserHandle = mChooserMultiProfilePagerAdapter.getCurrentUserHandle();
@@ -2855,7 +2855,7 @@ public class ChooserActivity extends ResolverActivity implements
@Override // ChooserListCommunicator
public int getMaxRankedTargets() {
- return getMaxTargetsPerRow();
+ return mMaxTargetsPerRow;
}
@Override // ChooserListCommunicator
@@ -3203,13 +3203,6 @@ public class ChooserActivity extends ResolverActivity implements
}
}
- int getMaxTargetsPerRow() {
- int maxTargets = MAX_TARGETS_PER_ROW_PORTRAIT;
- if (mShouldDisplayLandscape) {
- maxTargets = MAX_TARGETS_PER_ROW_LANDSCAPE;
- }
- return maxTargets;
- }
/**
* Adapter for all types of items and targets in ShareSheet.
* Note that ranked sections like Direct Share - while appearing grid-like - are handled on the
@@ -3277,7 +3270,11 @@ public class ChooserActivity extends ResolverActivity implements
return false;
}
- int newWidth = width / getMaxTargetsPerRow();
+ // Limit width to the maximum width of the chooser activity
+ int maxWidth = getResources().getDimensionPixelSize(R.dimen.chooser_width);
+ width = Math.min(maxWidth, width);
+
+ int newWidth = width / mMaxTargetsPerRow;
if (newWidth != mChooserTargetWidth) {
mChooserTargetWidth = newWidth;
return true;
@@ -3312,7 +3309,7 @@ public class ChooserActivity extends ResolverActivity implements
+ getAzLabelRowCount()
+ Math.ceil(
(float) mChooserListAdapter.getAlphaTargetCount()
- / getMaxTargetsPerRow())
+ / mMaxTargetsPerRow)
);
}
@@ -3352,7 +3349,7 @@ public class ChooserActivity extends ResolverActivity implements
public int getCallerAndRankedTargetRowCount() {
return (int) Math.ceil(
((float) mChooserListAdapter.getCallerTargetCount()
- + mChooserListAdapter.getRankedTargetCount()) / getMaxTargetsPerRow());
+ + mChooserListAdapter.getRankedTargetCount()) / mMaxTargetsPerRow);
}
// There can be at most one row in the listview, that is internally
@@ -3551,7 +3548,7 @@ public class ChooserActivity extends ResolverActivity implements
parentGroup.addView(row2);
mDirectShareViewHolder = new DirectShareViewHolder(parentGroup,
- Lists.newArrayList(row1, row2), getMaxTargetsPerRow(), viewType);
+ Lists.newArrayList(row1, row2), mMaxTargetsPerRow, viewType);
loadViewsIntoGroup(mDirectShareViewHolder);
return mDirectShareViewHolder;
@@ -3559,7 +3556,7 @@ public class ChooserActivity extends ResolverActivity implements
ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row, parent,
false);
ItemGroupViewHolder holder =
- new SingleRowViewHolder(row, getMaxTargetsPerRow(), viewType);
+ new SingleRowViewHolder(row, mMaxTargetsPerRow, viewType);
loadViewsIntoGroup(holder);
return holder;
@@ -3651,7 +3648,7 @@ public class ChooserActivity extends ResolverActivity implements
final int serviceCount = mChooserListAdapter.getServiceTargetCount();
final int serviceRows = (int) Math.ceil((float) serviceCount / getMaxRankedTargets());
if (position < serviceRows) {
- return position * getMaxTargetsPerRow();
+ return position * mMaxTargetsPerRow;
}
position -= serviceRows;
@@ -3660,7 +3657,7 @@ public class ChooserActivity extends ResolverActivity implements
+ mChooserListAdapter.getRankedTargetCount();
final int callerAndRankedRows = getCallerAndRankedTargetRowCount();
if (position < callerAndRankedRows) {
- return serviceCount + position * getMaxTargetsPerRow();
+ return serviceCount + position * mMaxTargetsPerRow;
}
position -= getAzLabelRowCount() + callerAndRankedRows;
@@ -3673,7 +3670,7 @@ public class ChooserActivity extends ResolverActivity implements
if (mDirectShareViewHolder != null && canExpandDirectShare) {
mDirectShareViewHolder.handleScroll(
mChooserMultiProfilePagerAdapter.getActiveAdapterView(), y, oldy,
- getMaxTargetsPerRow());
+ mMaxTargetsPerRow);
}
}
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c750eadf845a..6faa04690473 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -366,6 +366,7 @@ message ActivityRecordProto {
optional bool pip_auto_enter_enabled = 31;
optional bool in_size_compat_mode = 32;
optional float min_aspect_ratio = 33;
+ optional bool provides_max_bounds = 34;
}
/* represents WindowToken */
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 90caaccfbff4..933b4d243df9 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -20,8 +20,10 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_gravity="center"
android:maxCollapsedHeight="0dp"
android:maxCollapsedHeightSmall="56dp"
+ android:maxWidth="@dimen/chooser_width"
android:id="@id/contentPanel">
<RelativeLayout
diff --git a/core/res/res/layout/chooser_grid_preview_image.xml b/core/res/res/layout/chooser_grid_preview_image.xml
index 0d04d7f319b8..52692b03a44d 100644
--- a/core/res/res/layout/chooser_grid_preview_image.xml
+++ b/core/res/res/layout/chooser_grid_preview_image.xml
@@ -34,7 +34,7 @@
<view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
android:id="@+id/content_preview_image_1_large"
android:layout_width="120dp"
- android:layout_height="140dp"
+ android:layout_height="104dp"
android:layout_alignParentTop="true"
android:adjustViewBounds="true"
android:gravity="center"
@@ -44,7 +44,7 @@
android:id="@+id/content_preview_image_2_large"
android:visibility="gone"
android:layout_width="120dp"
- android:layout_height="140dp"
+ android:layout_height="104dp"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/content_preview_image_1_large"
android:layout_marginLeft="10dp"
diff --git a/core/res/res/values-sw600dp/config.xml b/core/res/res/values-sw600dp/config.xml
index 861e329f2de9..624581aba7dd 100644
--- a/core/res/res/values-sw600dp/config.xml
+++ b/core/res/res/values-sw600dp/config.xml
@@ -56,5 +56,7 @@
to be aligned to one side of the screen when in landscape mode. -->
<bool name="config_enableDynamicKeyguardPositioning">true</bool>
+ <integer name="config_chooser_max_targets_per_row">6</integer>
+
</resources>
diff --git a/core/res/res/values-sw600dp/dimens.xml b/core/res/res/values-sw600dp/dimens.xml
index 02ed848fc7f1..e8f15fd022d7 100644
--- a/core/res/res/values-sw600dp/dimens.xml
+++ b/core/res/res/values-sw600dp/dimens.xml
@@ -110,4 +110,7 @@
<dimen name="immersive_mode_cling_width">380dp</dimen>
<dimen name="floating_toolbar_preferred_width">544dp</dimen>
+
+ <dimen name="chooser_width">624dp</dimen>
+
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4d851644903e..1c31b1b76f85 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5284,4 +5284,6 @@
<string name="config_work_badge_path_24" translatable="false">
M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2z
</string>
+
+ <integer name="config_chooser_max_targets_per_row">4</integer>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 0706d8a8e4c6..f331f1ab720f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -900,7 +900,8 @@
<dimen name="seekbar_thumb_exclusion_max_size">48dp</dimen>
<!-- chooser/resolver (sharesheet) spacing -->
- <dimen name="chooser_corner_radius">16dp</dimen>
+ <dimen name="chooser_width">412dp</dimen>
+ <dimen name="chooser_corner_radius">28dp</dimen>
<dimen name="chooser_row_text_option_translate">25dp</dimen>
<dimen name="chooser_view_spacing">18dp</dimen>
<dimen name="chooser_edge_margin_thin">16dp</dimen>
@@ -917,7 +918,7 @@
<dimen name="resolver_icon_size">32dp</dimen>
<dimen name="resolver_button_bar_spacing">0dp</dimen>
<dimen name="resolver_badge_size">18dp</dimen>
- <dimen name="resolver_icon_margin">16dp</dimen>
+ <dimen name="resolver_icon_margin">8dp</dimen>
<dimen name="resolver_small_margin">18dp</dimen>
<dimen name="resolver_edge_margin">24dp</dimen>
<dimen name="resolver_elevation">1dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 54282bef00f0..b017a30cb5f2 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -275,6 +275,7 @@
<java-symbol type="bool" name="action_bar_expanded_action_views_exclusive" />
<java-symbol type="bool" name="config_avoidGfxAccel" />
<java-symbol type="bool" name="config_bluetooth_address_validation" />
+ <java-symbol type="integer" name="config_chooser_max_targets_per_row" />
<java-symbol type="bool" name="config_flipToScreenOffEnabled" />
<java-symbol type="integer" name="config_flipToScreenOffMaxLatencyMicros" />
<java-symbol type="bool" name="config_bluetooth_sco_off_call" />
@@ -2844,6 +2845,7 @@
<java-symbol type="layout" name="date_picker_month_item_material" />
<java-symbol type="id" name="month_view" />
<java-symbol type="integer" name="config_zen_repeat_callers_threshold" />
+ <java-symbol type="dimen" name="chooser_width" />
<java-symbol type="dimen" name="chooser_corner_radius" />
<java-symbol type="string" name="chooser_no_direct_share_targets" />
<java-symbol type="drawable" name="chooser_row_layer_list" />
diff --git a/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java b/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java
index 0456029f45a0..98485c024a59 100644
--- a/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java
+++ b/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java
@@ -18,8 +18,7 @@ package android.content.pm;
import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
import android.annotation.Nullable;
import android.platform.test.annotations.Presubmit;
@@ -146,24 +145,17 @@ public final class ConstrainDisplayApisConfigTest {
private static void testNeverConstrainDisplayApis(String packageName, long version,
boolean expected) {
- boolean result = ConstrainDisplayApisConfig.neverConstrainDisplayApis(
- buildApplicationInfo(packageName, version));
- if (expected) {
- assertTrue(result);
- } else {
- assertFalse(result);
- }
+ ConstrainDisplayApisConfig config = new ConstrainDisplayApisConfig();
+ assertEquals(expected,
+ config.getNeverConstrainDisplayApis(buildApplicationInfo(packageName, version)));
}
private static void testAlwaysConstrainDisplayApis(String packageName, long version,
boolean expected) {
- boolean result = ConstrainDisplayApisConfig.alwaysConstrainDisplayApis(
- buildApplicationInfo(packageName, version));
- if (expected) {
- assertTrue(result);
- } else {
- assertFalse(result);
- }
+ ConstrainDisplayApisConfig config = new ConstrainDisplayApisConfig();
+
+ assertEquals(expected,
+ config.getAlwaysConstrainDisplayApis(buildApplicationInfo(packageName, version)));
}
private static ApplicationInfo buildApplicationInfo(String packageName, long version) {
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 756425eedabb..0b8dc3fe0dec 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -180,6 +180,7 @@
<assign-permission name="android.permission.WATCH_APPOPS" uid="cameraserver" />
<assign-permission name="android.permission.MANAGE_APP_OPS_MODES" uid="cameraserver" />
<assign-permission name="android.permission.OBSERVE_SENSOR_PRIVACY" uid="cameraserver" />
+ <assign-permission name="android.permission.REAL_GET_TASKS" uid="cameraserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index af19bd0a79ac..b8e8b0114b47 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -295,11 +295,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
@NonNull TaskFragmentContainer primaryContainer, @NonNull Activity primaryActivity,
@NonNull TaskFragmentContainer secondaryContainer,
@NonNull SplitRule splitRule) {
+ SplitContainer splitContainer = new SplitContainer(primaryContainer, primaryActivity,
+ secondaryContainer, splitRule);
+ // Remove container later to prevent pinning escaping toast showing in lock task mode.
if (splitRule instanceof SplitPairRule && ((SplitPairRule) splitRule).shouldClearTop()) {
removeExistingSecondaryContainers(wct, primaryContainer);
}
- SplitContainer splitContainer = new SplitContainer(primaryContainer, primaryActivity,
- secondaryContainer, splitRule);
mSplitContainers.add(splitContainer);
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 81be21cbd7aa..ade573132eef 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -112,8 +112,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
// Set adjacent to each other so that the containers below will be invisible.
- setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(),
- secondaryContainer.getTaskFragmentToken(), rule);
+ setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule);
mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule);
@@ -149,8 +148,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
secondaryActivity, secondaryRectBounds, primaryContainer);
// Set adjacent to each other so that the containers below will be invisible.
- setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(),
- secondaryContainer.getTaskFragmentToken(), rule);
+ setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule);
mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule);
@@ -269,8 +267,22 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
resizeTaskFragmentIfRegistered(wct, secondaryContainer, secondaryRectBounds);
- setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(),
- secondaryContainer.getTaskFragmentToken(), rule);
+ setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule);
+ }
+
+ private void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentContainer primaryContainer,
+ @NonNull TaskFragmentContainer secondaryContainer, @NonNull SplitRule splitRule) {
+ final Rect parentBounds = getParentContainerBounds(primaryContainer);
+ // Clear adjacent TaskFragments if the container is shown in fullscreen, or the
+ // secondaryContainer could not be finished.
+ if (!shouldShowSideBySide(parentBounds, splitRule)) {
+ setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(),
+ null /* secondary */, null /* splitRule */);
+ } else {
+ setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(),
+ secondaryContainer.getTaskFragmentToken(), splitRule);
+ }
}
/**
diff --git a/libs/WindowManager/Shell/res/drawable/size_compat_hint_bubble.xml b/libs/WindowManager/Shell/res/drawable/compat_hint_bubble.xml
index 22cd384e1be0..26848b13a1bc 100644
--- a/libs/WindowManager/Shell/res/drawable/size_compat_hint_bubble.xml
+++ b/libs/WindowManager/Shell/res/drawable/compat_hint_bubble.xml
@@ -16,6 +16,6 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <solid android:color="@color/size_compat_background"/>
- <corners android:radius="@dimen/size_compat_hint_corner_radius"/>
+ <solid android:color="@color/compat_controls_background"/>
+ <corners android:radius="@dimen/compat_hint_corner_radius"/>
</shape> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/size_compat_hint_point.xml b/libs/WindowManager/Shell/res/drawable/compat_hint_point.xml
index af9063a94afb..0e0ca37aaf25 100644
--- a/libs/WindowManager/Shell/res/drawable/size_compat_hint_point.xml
+++ b/libs/WindowManager/Shell/res/drawable/compat_hint_point.xml
@@ -15,11 +15,11 @@
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/size_compat_hint_point_width"
+ android:width="@dimen/compat_hint_point_width"
android:height="8dp"
android:viewportWidth="10"
android:viewportHeight="8">
<path
- android:fillColor="@color/size_compat_background"
+ android:fillColor="@color/compat_controls_background"
android:pathData="M10,0 l-4.1875,6.6875 a1,1 0 0,1 -1.625,0 l-4.1875,-6.6875z"/>
</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml b/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml
index 18caa3582537..ab74e43472c3 100644
--- a/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml
+++ b/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml
@@ -20,16 +20,16 @@
android:viewportWidth="48"
android:viewportHeight="48">
<path
- android:fillColor="@color/size_compat_background"
+ android:fillColor="@color/compat_controls_background"
android:pathData="M0,24 a24,24 0 1,0 48,0 a24,24 0 1,0 -48,0" />
<group
android:translateX="12"
android:translateY="12">
<path
- android:fillColor="@color/size_compat_text"
+ android:fillColor="@color/compat_controls_text"
android:pathData="M6,13c0,-1.65 0.67,-3.15 1.76,-4.24L6.34,7.34C4.9,8.79 4,10.79 4,13c0,4.08 3.05,7.44 7,7.93v-2.02C8.17,18.43 6,15.97 6,13z"/>
<path
- android:fillColor="@color/size_compat_text"
+ android:fillColor="@color/compat_controls_text"
android:pathData="M20,13c0,-4.42 -3.58,-8 -8,-8c-0.06,0 -0.12,0.01 -0.18,0.01v0l1.09,-1.09L11.5,2.5L8,6l3.5,3.5l1.41,-1.41l-1.08,-1.08C11.89,7.01 11.95,7 12,7c3.31,0 6,2.69 6,6c0,2.97 -2.17,5.43 -5,5.91v2.02C16.95,20.44 20,17.08 20,13z"/>
</group>
</vector>
diff --git a/libs/WindowManager/Shell/res/layout/compat_mode_hint.xml b/libs/WindowManager/Shell/res/layout/compat_mode_hint.xml
new file mode 100644
index 000000000000..c04e258ea784
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/compat_mode_hint.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:clipToPadding="false"
+ android:paddingEnd="@dimen/compat_hint_padding_end"
+ android:paddingBottom="5dp"
+ android:clickable="true">
+
+ <TextView
+ android:id="@+id/compat_mode_hint_text"
+ android:layout_width="188dp"
+ android:layout_height="wrap_content"
+ android:lineSpacingExtra="4sp"
+ android:background="@drawable/compat_hint_bubble"
+ android:padding="16dp"
+ android:textAlignment="viewStart"
+ android:textColor="@color/compat_controls_text"
+ android:textSize="14sp"/>
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:src="@drawable/compat_hint_point"
+ android:paddingHorizontal="@dimen/compat_hint_corner_radius"
+ android:contentDescription="@null"/>
+
+</LinearLayout>
diff --git a/libs/WindowManager/Shell/res/layout/size_compat_ui.xml b/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml
index 82ebee263a64..6f946b25eaa5 100644
--- a/libs/WindowManager/Shell/res/layout/size_compat_ui.xml
+++ b/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml
@@ -14,10 +14,15 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.wm.shell.sizecompatui.SizeCompatRestartButton
+<com.android.wm.shell.compatui.CompatUILayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="bottom|end">
+
+ <include android:id="@+id/size_compat_hint"
+ layout="@layout/compat_mode_hint"/>
<FrameLayout
android:layout_width="@dimen/size_compat_button_width"
@@ -36,4 +41,4 @@
</FrameLayout>
-</com.android.wm.shell.sizecompatui.SizeCompatRestartButton>
+</com.android.wm.shell.compatui.CompatUILayout>
diff --git a/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml b/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml
deleted file mode 100644
index d0e7c42dbf8b..000000000000
--- a/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2019 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.
--->
-<com.android.wm.shell.sizecompatui.SizeCompatHintPopup
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
- <FrameLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:clipToPadding="false"
- android:paddingBottom="5dp">
-
- <LinearLayout
- android:id="@+id/size_compat_hint_popup"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:clickable="true">
-
- <TextView
- android:layout_width="188dp"
- android:layout_height="wrap_content"
- android:lineSpacingExtra="4sp"
- android:background="@drawable/size_compat_hint_bubble"
- android:padding="16dp"
- android:text="@string/restart_button_description"
- android:textAlignment="viewStart"
- android:textColor="@color/size_compat_text"
- android:textSize="14sp"/>
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end"
- android:src="@drawable/size_compat_hint_point"
- android:paddingHorizontal="@dimen/size_compat_hint_corner_radius"
- android:contentDescription="@null"/>
-
- </LinearLayout>
-
- </FrameLayout>
-
-</com.android.wm.shell.sizecompatui.SizeCompatHintPopup>
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index 23a21724e43d..cf596f7d15dc 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -30,9 +30,9 @@
<color name="bubbles_dark">@color/GM2_grey_800</color>
<color name="bubbles_icon_tint">@color/GM2_grey_700</color>
- <!-- Size Compat Restart Button -->
- <color name="size_compat_background">@android:color/system_neutral1_800</color>
- <color name="size_compat_text">@android:color/system_neutral1_50</color>
+ <!-- Compat controls UI -->
+ <color name="compat_controls_background">@android:color/system_neutral1_800</color>
+ <color name="compat_controls_text">@android:color/system_neutral1_50</color>
<!-- GM2 colors -->
<color name="GM2_grey_200">#E8EAED</color>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 9e77578eafd8..18e91f41a698 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -206,11 +206,15 @@
<!-- The height of the size compat restart button including padding. -->
<dimen name="size_compat_button_height">64dp</dimen>
- <!-- The radius of the corners of the size compat hint bubble. -->
- <dimen name="size_compat_hint_corner_radius">28dp</dimen>
+ <!-- The radius of the corners of the compat hint bubble. -->
+ <dimen name="compat_hint_corner_radius">28dp</dimen>
- <!-- The width of the size compat hint point. -->
- <dimen name="size_compat_hint_point_width">10dp</dimen>
+ <!-- The width of the compat hint point. -->
+ <dimen name="compat_hint_point_width">10dp</dimen>
+
+ <!-- The end padding for the compat hint. Computed as (size_compat_button_width / 2
+ - compat_hint_corner_radius - compat_hint_point_width /2). -->
+ <dimen name="compat_hint_padding_end">7dp</dimen>
<!-- The width of the brand image on staring surface. -->
<dimen name="starting_surface_brand_image_width">200dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 8e98b82088dc..8b3a35688f11 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -52,8 +52,8 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.compatui.CompatUIController;
import com.android.wm.shell.recents.RecentTasksController;
-import com.android.wm.shell.sizecompatui.SizeCompatUIController;
import com.android.wm.shell.startingsurface.StartingWindowController;
import java.io.PrintWriter;
@@ -69,7 +69,7 @@ import java.util.function.Consumer;
* TODO(b/167582004): may consider consolidating this class and TaskOrganizer
*/
public class ShellTaskOrganizer extends TaskOrganizer implements
- SizeCompatUIController.SizeCompatUICallback {
+ CompatUIController.CompatUICallback {
// Intentionally using negative numbers here so the positive numbers can be used
// for task id specific listeners that will be added later.
@@ -98,9 +98,9 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
default void onTaskInfoChanged(RunningTaskInfo taskInfo) {}
default void onTaskVanished(RunningTaskInfo taskInfo) {}
default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {}
- /** Whether this task listener supports size compat UI. */
- default boolean supportSizeCompatUI() {
- // All TaskListeners should support size compat except PIP.
+ /** Whether this task listener supports compat UI. */
+ default boolean supportCompatUI() {
+ // All TaskListeners should support compat UI except PIP.
return true;
}
/** Attaches the a child window surface to the task surface. */
@@ -159,11 +159,11 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
private StartingWindowController mStartingWindow;
/**
- * In charge of showing size compat UI. Can be {@code null} if device doesn't support size
+ * In charge of showing compat UI. Can be {@code null} if device doesn't support size
* compat.
*/
@Nullable
- private final SizeCompatUIController mSizeCompatUI;
+ private final CompatUIController mCompatUI;
@Nullable
private final Optional<RecentTasksController> mRecentTasks;
@@ -172,32 +172,32 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
private RunningTaskInfo mLastFocusedTaskInfo;
public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context) {
- this(null /* taskOrganizerController */, mainExecutor, context, null /* sizeCompatUI */,
+ this(null /* taskOrganizerController */, mainExecutor, context, null /* compatUI */,
Optional.empty() /* recentTasksController */);
}
public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context, @Nullable
- SizeCompatUIController sizeCompatUI) {
- this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI,
+ CompatUIController compatUI) {
+ this(null /* taskOrganizerController */, mainExecutor, context, compatUI,
Optional.empty() /* recentTasksController */);
}
public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context, @Nullable
- SizeCompatUIController sizeCompatUI,
+ CompatUIController compatUI,
Optional<RecentTasksController> recentTasks) {
- this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI,
+ this(null /* taskOrganizerController */, mainExecutor, context, compatUI,
recentTasks);
}
@VisibleForTesting
ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController, ShellExecutor mainExecutor,
- Context context, @Nullable SizeCompatUIController sizeCompatUI,
+ Context context, @Nullable CompatUIController compatUI,
Optional<RecentTasksController> recentTasks) {
super(taskOrganizerController, mainExecutor);
- mSizeCompatUI = sizeCompatUI;
+ mCompatUI = compatUI;
mRecentTasks = recentTasks;
- if (sizeCompatUI != null) {
- sizeCompatUI.setSizeCompatUICallback(this);
+ if (compatUI != null) {
+ compatUI.setCompatUICallback(this);
}
}
@@ -428,7 +428,7 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
listener.onTaskAppeared(info.getTaskInfo(), info.getLeash());
}
notifyLocusVisibilityIfNeeded(info.getTaskInfo());
- notifySizeCompatUI(info.getTaskInfo(), listener);
+ notifyCompatUI(info.getTaskInfo(), listener);
}
/**
@@ -459,8 +459,8 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
}
notifyLocusVisibilityIfNeeded(taskInfo);
if (updated || !taskInfo.equalsForSizeCompat(data.getTaskInfo())) {
- // Notify the size compat UI if the listener or task info changed.
- notifySizeCompatUI(taskInfo, newListener);
+ // Notify the compat UI if the listener or task info changed.
+ notifyCompatUI(taskInfo, newListener);
}
if (data.getTaskInfo().getWindowingMode() != taskInfo.getWindowingMode()) {
// Notify the recent tasks when a task changes windowing modes
@@ -504,8 +504,8 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
listener.onTaskVanished(taskInfo);
}
notifyLocusVisibilityIfNeeded(taskInfo);
- // Pass null for listener to remove the size compat UI on this task if there is any.
- notifySizeCompatUI(taskInfo, null /* taskListener */);
+ // Pass null for listener to remove the compat UI on this task if there is any.
+ notifyCompatUI(taskInfo, null /* taskListener */);
// Notify the recent tasks that a task has been removed
mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskRemoved(taskInfo));
}
@@ -618,28 +618,28 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
}
/**
- * Notifies {@link SizeCompatUIController} about the size compat info changed on the give Task
+ * Notifies {@link CompatUIController} about the compat info changed on the give Task
* to update the UI accordingly.
*
* @param taskInfo the new Task info
* @param taskListener listener to handle the Task Surface placement. {@code null} if task is
* vanished.
*/
- private void notifySizeCompatUI(RunningTaskInfo taskInfo, @Nullable TaskListener taskListener) {
- if (mSizeCompatUI == null) {
+ private void notifyCompatUI(RunningTaskInfo taskInfo, @Nullable TaskListener taskListener) {
+ if (mCompatUI == null) {
return;
}
- // The task is vanished or doesn't support size compat UI, notify to remove size compat UI
+ // The task is vanished or doesn't support compat UI, notify to remove compat UI
// on this Task if there is any.
- if (taskListener == null || !taskListener.supportSizeCompatUI()
+ if (taskListener == null || !taskListener.supportCompatUI()
|| !taskInfo.topActivityInSizeCompat || !taskInfo.isVisible) {
- mSizeCompatUI.onSizeCompatInfoChanged(taskInfo.displayId, taskInfo.taskId,
+ mCompatUI.onCompatInfoChanged(taskInfo.displayId, taskInfo.taskId,
null /* taskConfig */, null /* taskListener */);
return;
}
- mSizeCompatUI.onSizeCompatInfoChanged(taskInfo.displayId, taskInfo.taskId,
+ mCompatUI.onCompatInfoChanged(taskInfo.displayId, taskInfo.taskId,
taskInfo.configuration, taskListener);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 519a856538c7..cd635c10fd8e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -328,6 +328,7 @@ public class BubbleData {
if (prevBubble == null) {
// Create a new bubble
bubble.setSuppressFlyout(suppressFlyout);
+ bubble.markUpdatedAt(mTimeSource.currentTimeMillis());
doAdd(bubble);
trim();
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUI.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUI.java
index a703114194a0..99dbfe01964c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUI.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUI.java
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package com.android.wm.shell.sizecompatui;
+package com.android.wm.shell.compatui;
import com.android.wm.shell.common.annotations.ExternalThread;
/**
- * Interface to engage size compat UI.
+ * Interface to engage compat UI.
*/
@ExternalThread
-public interface SizeCompatUI {
+public interface CompatUI {
/**
- * Called when the keyguard occluded state changes. Removes all size compat UIs if the
+ * Called when the keyguard occluded state changes. Removes all compat UIs if the
* keyguard is now occluded.
* @param occluded indicates if the keyguard is now occluded.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index e06070ab12e5..e0b23873a980 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.sizecompatui;
+package com.android.wm.shell.compatui;
import android.annotation.Nullable;
import android.content.Context;
@@ -48,20 +48,20 @@ import java.util.function.Predicate;
/**
* Controls to show/update restart-activity buttons on Tasks based on whether the foreground
- * activities are in size compatibility mode.
+ * activities are in compatibility mode.
*/
-public class SizeCompatUIController implements OnDisplaysChangedListener,
+public class CompatUIController implements OnDisplaysChangedListener,
DisplayImeController.ImePositionProcessor {
/** Callback for size compat UI interaction. */
- public interface SizeCompatUICallback {
+ public interface CompatUICallback {
/** Called when the size compat restart button appears. */
void onSizeCompatRestartButtonAppeared(int taskId);
/** Called when the size compat restart button is clicked. */
void onSizeCompatRestartButtonClicked(int taskId);
}
- private static final String TAG = "SizeCompatUIController";
+ private static final String TAG = "CompatUIController";
/** Whether the IME is shown on display id. */
private final Set<Integer> mDisplaysWithIme = new ArraySet<>(1);
@@ -71,7 +71,7 @@ public class SizeCompatUIController implements OnDisplaysChangedListener,
new SparseArray<>(0);
/** The showing UIs by task id. */
- private final SparseArray<SizeCompatUILayout> mActiveLayouts = new SparseArray<>(0);
+ private final SparseArray<CompatUIWindowManager> mActiveLayouts = new SparseArray<>(0);
/** Avoid creating display context frequently for non-default display. */
private final SparseArray<WeakReference<Context>> mDisplayContextCache = new SparseArray<>(0);
@@ -82,17 +82,17 @@ public class SizeCompatUIController implements OnDisplaysChangedListener,
private final DisplayImeController mImeController;
private final SyncTransactionQueue mSyncQueue;
private final ShellExecutor mMainExecutor;
- private final SizeCompatUIImpl mImpl = new SizeCompatUIImpl();
+ private final CompatUIImpl mImpl = new CompatUIImpl();
- private SizeCompatUICallback mCallback;
+ private CompatUICallback mCallback;
/** Only show once automatically in the process life. */
private boolean mHasShownHint;
- /** Indicates if the keyguard is currently occluded, in which case size compat UIs shouldn't
+ /** Indicates if the keyguard is currently occluded, in which case compat UIs shouldn't
* be shown. */
private boolean mKeyguardOccluded;
- public SizeCompatUIController(Context context,
+ public CompatUIController(Context context,
DisplayController displayController,
DisplayInsetsController displayInsetsController,
DisplayImeController imeController,
@@ -108,35 +108,36 @@ public class SizeCompatUIController implements OnDisplaysChangedListener,
mImeController.addPositionProcessor(this);
}
- public SizeCompatUI asSizeCompatUI() {
+ /** Returns implementation of {@link CompatUI}. */
+ public CompatUI asCompatUI() {
return mImpl;
}
/** Sets the callback for UI interactions. */
- public void setSizeCompatUICallback(SizeCompatUICallback callback) {
+ public void setCompatUICallback(CompatUICallback callback) {
mCallback = callback;
}
/**
- * Called when the Task info changed. Creates and updates the size compat UI if there is an
+ * Called when the Task info changed. Creates and updates the compat UI if there is an
* activity in size compat, or removes the UI if there is no size compat activity.
*
* @param displayId display the task and activity are in.
* @param taskId task the activity is in.
- * @param taskConfig task config to place the size compat UI with.
+ * @param taskConfig task config to place the compat UI with.
* @param taskListener listener to handle the Task Surface placement.
*/
- public void onSizeCompatInfoChanged(int displayId, int taskId,
+ public void onCompatInfoChanged(int displayId, int taskId,
@Nullable Configuration taskConfig,
@Nullable ShellTaskOrganizer.TaskListener taskListener) {
if (taskConfig == null || taskListener == null) {
- // Null token means the current foreground activity is not in size compatibility mode.
+ // Null token means the current foreground activity is not in compatibility mode.
removeLayout(taskId);
} else if (mActiveLayouts.contains(taskId)) {
// UI already exists, update the UI layout.
updateLayout(taskId, taskConfig, taskListener);
} else {
- // Create a new size compat UI.
+ // Create a new compat UI.
createLayout(displayId, taskId, taskConfig, taskListener);
}
}
@@ -151,7 +152,7 @@ public class SizeCompatUIController implements OnDisplaysChangedListener,
mDisplayContextCache.remove(displayId);
removeOnInsetsChangedListener(displayId);
- // Remove all size compat UIs on the removed display.
+ // Remove all compat UIs on the removed display.
final List<Integer> toRemoveTaskIds = new ArrayList<>();
forAllLayoutsOnDisplay(displayId, layout -> toRemoveTaskIds.add(layout.getTaskId()));
for (int i = toRemoveTaskIds.size() - 1; i >= 0; i--) {
@@ -194,7 +195,7 @@ public class SizeCompatUIController implements OnDisplaysChangedListener,
mDisplaysWithIme.remove(displayId);
}
- // Hide the size compat UIs when input method is showing.
+ // Hide the compat UIs when input method is showing.
forAllLayoutsOnDisplay(displayId,
layout -> layout.updateVisibility(showOnDisplay(displayId)));
}
@@ -202,7 +203,7 @@ public class SizeCompatUIController implements OnDisplaysChangedListener,
@VisibleForTesting
void onKeyguardOccludedChanged(boolean occluded) {
mKeyguardOccluded = occluded;
- // Hide the size compat UIs when keyguard is occluded.
+ // Hide the compat UIs when keyguard is occluded.
forAllLayouts(layout -> layout.updateVisibility(showOnDisplay(layout.getDisplayId())));
}
@@ -222,34 +223,34 @@ public class SizeCompatUIController implements OnDisplaysChangedListener,
return;
}
- final SizeCompatUILayout layout = createLayout(context, displayId, taskId, taskConfig,
- taskListener);
- mActiveLayouts.put(taskId, layout);
- layout.createSizeCompatButton(showOnDisplay(displayId));
+ final CompatUIWindowManager compatUIWindowManager =
+ createLayout(context, displayId, taskId, taskConfig, taskListener);
+ mActiveLayouts.put(taskId, compatUIWindowManager);
+ compatUIWindowManager.createLayout(showOnDisplay(displayId));
}
@VisibleForTesting
- SizeCompatUILayout createLayout(Context context, int displayId, int taskId,
+ CompatUIWindowManager createLayout(Context context, int displayId, int taskId,
Configuration taskConfig, ShellTaskOrganizer.TaskListener taskListener) {
- final SizeCompatUILayout layout = new SizeCompatUILayout(mSyncQueue, mCallback, context,
- taskConfig, taskId, taskListener, mDisplayController.getDisplayLayout(displayId),
- mHasShownHint);
+ final CompatUIWindowManager compatUIWindowManager = new CompatUIWindowManager(context,
+ taskConfig, mSyncQueue, mCallback, taskId, taskListener,
+ mDisplayController.getDisplayLayout(displayId), mHasShownHint);
// Only show hint for the first time.
mHasShownHint = true;
- return layout;
+ return compatUIWindowManager;
}
private void updateLayout(int taskId, Configuration taskConfig,
ShellTaskOrganizer.TaskListener taskListener) {
- final SizeCompatUILayout layout = mActiveLayouts.get(taskId);
+ final CompatUIWindowManager layout = mActiveLayouts.get(taskId);
if (layout == null) {
return;
}
- layout.updateSizeCompatInfo(taskConfig, taskListener, showOnDisplay(layout.getDisplayId()));
+ layout.updateCompatInfo(taskConfig, taskListener, showOnDisplay(layout.getDisplayId()));
}
private void removeLayout(int taskId) {
- final SizeCompatUILayout layout = mActiveLayouts.get(taskId);
+ final CompatUIWindowManager layout = mActiveLayouts.get(taskId);
if (layout != null) {
layout.release();
mActiveLayouts.remove(taskId);
@@ -275,19 +276,19 @@ public class SizeCompatUIController implements OnDisplaysChangedListener,
return context;
}
- private void forAllLayoutsOnDisplay(int displayId, Consumer<SizeCompatUILayout> callback) {
+ private void forAllLayoutsOnDisplay(int displayId, Consumer<CompatUIWindowManager> callback) {
forAllLayouts(layout -> layout.getDisplayId() == displayId, callback);
}
- private void forAllLayouts(Consumer<SizeCompatUILayout> callback) {
+ private void forAllLayouts(Consumer<CompatUIWindowManager> callback) {
forAllLayouts(layout -> true, callback);
}
- private void forAllLayouts(Predicate<SizeCompatUILayout> condition,
- Consumer<SizeCompatUILayout> callback) {
+ private void forAllLayouts(Predicate<CompatUIWindowManager> condition,
+ Consumer<CompatUIWindowManager> callback) {
for (int i = 0; i < mActiveLayouts.size(); i++) {
final int taskId = mActiveLayouts.keyAt(i);
- final SizeCompatUILayout layout = mActiveLayouts.get(taskId);
+ final CompatUIWindowManager layout = mActiveLayouts.get(taskId);
if (layout != null && condition.test(layout)) {
callback.accept(layout);
}
@@ -298,11 +299,11 @@ public class SizeCompatUIController implements OnDisplaysChangedListener,
* The interface for calls from outside the Shell, within the host process.
*/
@ExternalThread
- private class SizeCompatUIImpl implements SizeCompatUI {
+ private class CompatUIImpl implements CompatUI {
@Override
public void onKeyguardOccludedChanged(boolean occluded) {
mMainExecutor.execute(() -> {
- SizeCompatUIController.this.onKeyguardOccludedChanged(occluded);
+ CompatUIController.this.onKeyguardOccludedChanged(occluded);
});
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java
new file mode 100644
index 000000000000..ea4f20968438
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.wm.shell.R;
+
+/**
+ * Container for compat UI controls.
+ */
+public class CompatUILayout extends LinearLayout {
+
+ private CompatUIWindowManager mWindowManager;
+
+ public CompatUILayout(Context context) {
+ this(context, null);
+ }
+
+ public CompatUILayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public CompatUILayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public CompatUILayout(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ void inject(CompatUIWindowManager windowManager) {
+ mWindowManager = windowManager;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ // Need to relayout after changes like hiding / showing a hint since they affect size.
+ // Doing this directly in setSizeCompatHintVisibility can result in flaky animation.
+ mWindowManager.relayout();
+ }
+
+ void setSizeCompatHintVisibility(boolean show) {
+ final LinearLayout sizeCompatHint = findViewById(R.id.size_compat_hint);
+ int visibility = show ? View.VISIBLE : View.GONE;
+ if (sizeCompatHint.getVisibility() == visibility) {
+ return;
+ }
+ sizeCompatHint.setVisibility(visibility);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ final ImageButton restartButton = findViewById(R.id.size_compat_restart_button);
+ restartButton.setOnClickListener(view -> mWindowManager.onRestartButtonClicked());
+ restartButton.setOnLongClickListener(view -> {
+ mWindowManager.onRestartButtonLongClicked();
+ return true;
+ });
+
+ final LinearLayout sizeCompatHint = findViewById(R.id.size_compat_hint);
+ ((TextView) sizeCompatHint.findViewById(R.id.compat_mode_hint_text))
+ .setText(R.string.restart_button_description);
+ sizeCompatHint.setOnClickListener(view -> setSizeCompatHintVisibility(/* show= */ false));
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
new file mode 100644
index 000000000000..997ad04e3b57
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui;
+
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.util.Log;
+import android.view.IWindow;
+import android.view.LayoutInflater;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.SurfaceSession;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowlessWindowManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.SyncTransactionQueue;
+
+/**
+ * Holds view hierarchy of a root surface and helps to inflate and manage layout for compat
+ * controls.
+ */
+class CompatUIWindowManager extends WindowlessWindowManager {
+
+ private static final String TAG = "CompatUIWindowManager";
+
+ private final SyncTransactionQueue mSyncQueue;
+ private final CompatUIController.CompatUICallback mCallback;
+ private final int mDisplayId;
+ private final int mTaskId;
+ private final Rect mStableBounds;
+
+ private Context mContext;
+ private Configuration mTaskConfig;
+ private ShellTaskOrganizer.TaskListener mTaskListener;
+ private DisplayLayout mDisplayLayout;
+
+ @VisibleForTesting
+ boolean mShouldShowHint;
+
+ @Nullable
+ @VisibleForTesting
+ CompatUILayout mCompatUILayout;
+
+ @Nullable
+ private SurfaceControlViewHost mViewHost;
+ @Nullable
+ private SurfaceControl mLeash;
+
+ CompatUIWindowManager(Context context, Configuration taskConfig,
+ SyncTransactionQueue syncQueue, CompatUIController.CompatUICallback callback,
+ int taskId, ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout,
+ boolean hasShownHint) {
+ super(taskConfig, null /* rootSurface */, null /* hostInputToken */);
+ mContext = context;
+ mSyncQueue = syncQueue;
+ mCallback = callback;
+ mTaskConfig = taskConfig;
+ mDisplayId = mContext.getDisplayId();
+ mTaskId = taskId;
+ mTaskListener = taskListener;
+ mDisplayLayout = displayLayout;
+ mShouldShowHint = !hasShownHint;
+ mStableBounds = new Rect();
+ mDisplayLayout.getStableBounds(mStableBounds);
+ }
+
+ @Override
+ public void setConfiguration(Configuration configuration) {
+ super.setConfiguration(configuration);
+ mContext = mContext.createConfigurationContext(configuration);
+ }
+
+ @Override
+ protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+ // Can't set position for the ViewRootImpl SC directly. Create a leash to manipulate later.
+ final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
+ .setContainerLayer()
+ .setName("CompatUILeash")
+ .setHidden(false)
+ .setCallsite("CompatUIWindowManager#attachToParentSurface");
+ attachToParentSurface(builder);
+ mLeash = builder.build();
+ b.setParent(mLeash);
+ }
+
+ /** Creates the layout for compat controls. */
+ void createLayout(boolean show) {
+ if (!show || mCompatUILayout != null) {
+ // Wait until compat controls should be visible.
+ return;
+ }
+
+ initCompatUi();
+ updateSurfacePosition();
+
+ mCallback.onSizeCompatRestartButtonAppeared(mTaskId);
+ }
+
+ /** Called when compat info changed. */
+ void updateCompatInfo(Configuration taskConfig,
+ ShellTaskOrganizer.TaskListener taskListener, boolean show) {
+ final Configuration prevTaskConfig = mTaskConfig;
+ final ShellTaskOrganizer.TaskListener prevTaskListener = mTaskListener;
+ mTaskConfig = taskConfig;
+ mTaskListener = taskListener;
+
+ // Update configuration.
+ mContext = mContext.createConfigurationContext(taskConfig);
+ setConfiguration(taskConfig);
+
+ if (mCompatUILayout == null || prevTaskListener != taskListener) {
+ // TaskListener changed, recreate the layout for new surface parent.
+ release();
+ createLayout(show);
+ return;
+ }
+
+ if (!taskConfig.windowConfiguration.getBounds()
+ .equals(prevTaskConfig.windowConfiguration.getBounds())) {
+ // Reposition the UI surfaces.
+ updateSurfacePosition();
+ }
+
+ if (taskConfig.getLayoutDirection() != prevTaskConfig.getLayoutDirection()) {
+ // Update layout for RTL.
+ mCompatUILayout.setLayoutDirection(taskConfig.getLayoutDirection());
+ updateSurfacePosition();
+ }
+ }
+
+ /** Called when the visibility of the UI should change. */
+ void updateVisibility(boolean show) {
+ if (mCompatUILayout == null) {
+ // Layout may not have been created because it was hidden previously.
+ createLayout(show);
+ return;
+ }
+
+ // Hide compat UIs when IME is showing.
+ final int newVisibility = show ? View.VISIBLE : View.GONE;
+ if (mCompatUILayout.getVisibility() != newVisibility) {
+ mCompatUILayout.setVisibility(newVisibility);
+ }
+ }
+
+ /** Called when display layout changed. */
+ void updateDisplayLayout(DisplayLayout displayLayout) {
+ final Rect prevStableBounds = mStableBounds;
+ final Rect curStableBounds = new Rect();
+ displayLayout.getStableBounds(curStableBounds);
+ mDisplayLayout = displayLayout;
+ if (!prevStableBounds.equals(curStableBounds)) {
+ // Stable bounds changed, update UI surface positions.
+ updateSurfacePosition();
+ mStableBounds.set(curStableBounds);
+ }
+ }
+
+ /** Called when it is ready to be placed compat UI surface. */
+ void attachToParentSurface(SurfaceControl.Builder b) {
+ mTaskListener.attachChildSurfaceToTask(mTaskId, b);
+ }
+
+ /** Called when the restart button is clicked. */
+ void onRestartButtonClicked() {
+ mCallback.onSizeCompatRestartButtonClicked(mTaskId);
+ }
+
+ /** Called when the restart button is long clicked. */
+ void onRestartButtonLongClicked() {
+ if (mCompatUILayout == null) {
+ return;
+ }
+ mCompatUILayout.setSizeCompatHintVisibility(/* show= */ true);
+ }
+
+ int getDisplayId() {
+ return mDisplayId;
+ }
+
+ int getTaskId() {
+ return mTaskId;
+ }
+
+ /** Releases the surface control and tears down the view hierarchy. */
+ void release() {
+ mCompatUILayout = null;
+
+ if (mViewHost != null) {
+ mViewHost.release();
+ mViewHost = null;
+ }
+
+ if (mLeash != null) {
+ final SurfaceControl leash = mLeash;
+ mSyncQueue.runInSync(t -> t.remove(leash));
+ mLeash = null;
+ }
+ }
+
+ void relayout() {
+ mViewHost.relayout(getWindowLayoutParams());
+ updateSurfacePosition();
+ }
+
+ @VisibleForTesting
+ void updateSurfacePosition() {
+ if (mCompatUILayout == null || mLeash == null) {
+ return;
+ }
+
+ // Use stable bounds to prevent controls from overlapping with system bars.
+ final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
+ final Rect stableBounds = new Rect();
+ mDisplayLayout.getStableBounds(stableBounds);
+ stableBounds.intersect(taskBounds);
+
+ // Position of the button in the container coordinate.
+ final int positionX = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
+ ? stableBounds.left - taskBounds.left
+ : stableBounds.right - taskBounds.left - mCompatUILayout.getMeasuredWidth();
+ final int positionY = stableBounds.bottom - taskBounds.top
+ - mCompatUILayout.getMeasuredHeight();
+
+ updateSurfacePosition(positionX, positionY);
+ }
+
+ private int getLayoutDirection() {
+ return mContext.getResources().getConfiguration().getLayoutDirection();
+ }
+
+ private void updateSurfacePosition(int positionX, int positionY) {
+ mSyncQueue.runInSync(t -> {
+ if (mLeash == null || !mLeash.isValid()) {
+ Log.w(TAG, "The leash has been released.");
+ return;
+ }
+ t.setPosition(mLeash, positionX, positionY);
+ // The compat UI should be the topmost child of the Task in case there can be more
+ // than one children.
+ t.setLayer(mLeash, Integer.MAX_VALUE);
+ });
+ }
+
+ /** Inflates {@link CompatUILayout} on to the root surface. */
+ private void initCompatUi() {
+ if (mViewHost != null) {
+ throw new IllegalStateException(
+ "A UI has already been created with this window manager.");
+ }
+
+ // Construction extracted into the separate methods to allow injection for tests.
+ mViewHost = createSurfaceViewHost();
+ mCompatUILayout = inflateCompatUILayout();
+ mCompatUILayout.inject(this);
+
+ mCompatUILayout.setSizeCompatHintVisibility(mShouldShowHint);
+
+ mViewHost.setView(mCompatUILayout, getWindowLayoutParams());
+
+ // Only show by default for the first time.
+ mShouldShowHint = false;
+ }
+
+ @VisibleForTesting
+ CompatUILayout inflateCompatUILayout() {
+ return (CompatUILayout) LayoutInflater.from(mContext)
+ .inflate(R.layout.compat_ui_layout, null);
+ }
+
+ @VisibleForTesting
+ SurfaceControlViewHost createSurfaceViewHost() {
+ return new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+ }
+
+ /** Gets the layout params. */
+ private WindowManager.LayoutParams getWindowLayoutParams() {
+ // Measure how big the hint is since its size depends on the text size.
+ mCompatUILayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ final WindowManager.LayoutParams winParams = new WindowManager.LayoutParams(
+ // Cannot be wrap_content as this determines the actual window size
+ mCompatUILayout.getMeasuredWidth(), mCompatUILayout.getMeasuredHeight(),
+ TYPE_APPLICATION_OVERLAY,
+ FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,
+ PixelFormat.TRANSLUCENT);
+ winParams.token = new Binder();
+ winParams.setTitle(CompatUILayout.class.getSimpleName() + mTaskId);
+ winParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
+ return winParams;
+ }
+
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 9500e8aecb57..6d4b2fa60b55 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -54,6 +54,8 @@ import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ShellAnimationThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
+import com.android.wm.shell.compatui.CompatUI;
+import com.android.wm.shell.compatui.CompatUIController;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.displayareahelper.DisplayAreaHelperController;
import com.android.wm.shell.draganddrop.DragAndDrop;
@@ -75,8 +77,6 @@ import com.android.wm.shell.pip.phone.PipAppOpsListener;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.recents.RecentTasks;
import com.android.wm.shell.recents.RecentTasksController;
-import com.android.wm.shell.sizecompatui.SizeCompatUI;
-import com.android.wm.shell.sizecompatui.SizeCompatUIController;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.startingsurface.StartingSurface;
@@ -173,25 +173,25 @@ public abstract class WMShellBaseModule {
@Provides
static ShellTaskOrganizer provideShellTaskOrganizer(@ShellMainThread ShellExecutor mainExecutor,
Context context,
- SizeCompatUIController sizeCompatUI,
+ CompatUIController compatUI,
Optional<RecentTasksController> recentTasksOptional
) {
- return new ShellTaskOrganizer(mainExecutor, context, sizeCompatUI, recentTasksOptional);
+ return new ShellTaskOrganizer(mainExecutor, context, compatUI, recentTasksOptional);
}
@WMSingleton
@Provides
- static SizeCompatUI provideSizeCompatUI(SizeCompatUIController sizeCompatUIController) {
- return sizeCompatUIController.asSizeCompatUI();
+ static CompatUI provideCompatUI(CompatUIController compatUIController) {
+ return compatUIController.asCompatUI();
}
@WMSingleton
@Provides
- static SizeCompatUIController provideSizeCompatUIController(Context context,
+ static CompatUIController provideCompatUIController(Context context,
DisplayController displayController, DisplayInsetsController displayInsetsController,
DisplayImeController imeController, SyncTransactionQueue syncQueue,
@ShellMainThread ShellExecutor mainExecutor) {
- return new SizeCompatUIController(context, displayController, displayInsetsController,
+ return new CompatUIController(context, displayController, displayInsetsController,
imeController, syncQueue, mainExecutor);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 854fc60e15e8..f0b2716f05d8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -778,8 +778,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
@Override
- public boolean supportSizeCompatUI() {
- // PIP doesn't support size compat.
+ public boolean supportCompatUI() {
+ // PIP doesn't support compat.
return false;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index eb512afa644d..101a55d8d367 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -191,6 +191,7 @@ public class PhonePipMenuController implements PipMenuController {
mSystemWindows.addView(mPipMenuView,
getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
0, SHELL_ROOT_LAYER_PIP);
+ setShellRootAccessibilityWindow();
}
private void detachPipMenuView() {
@@ -546,6 +547,10 @@ public class PhonePipMenuController implements PipMenuController {
mListeners.forEach(l -> l.onPipMenuStateChangeFinish(menuState));
}
mMenuState = menuState;
+ setShellRootAccessibilityWindow();
+ }
+
+ private void setShellRootAccessibilityWindow() {
switch (mMenuState) {
case MENU_STATE_NONE:
mSystemWindows.setShellRootAccessibilityWindow(0, SHELL_ROOT_LAYER_PIP, null);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index 8467cc5fc591..92a359891003 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -122,7 +122,7 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
if (mTargetViewContainer != null) {
// init can be called multiple times, remove the old one from view hierarchy first.
- mWindowManager.removeViewImmediate(mTargetViewContainer);
+ cleanUpDismissTarget();
}
mTargetView = new DismissCircleView(mContext);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopup.java
deleted file mode 100644
index ff6f913207f6..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopup.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.sizecompatui;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-
-import androidx.annotation.Nullable;
-
-import com.android.wm.shell.R;
-
-/** Popup to show the hint about the {@link SizeCompatRestartButton}. */
-public class SizeCompatHintPopup extends FrameLayout implements View.OnClickListener {
-
- private SizeCompatUILayout mLayout;
-
- public SizeCompatHintPopup(Context context) {
- super(context);
- }
-
- public SizeCompatHintPopup(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
-
- public SizeCompatHintPopup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public SizeCompatHintPopup(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- void inject(SizeCompatUILayout layout) {
- mLayout = layout;
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- final LinearLayout hintPopup = findViewById(R.id.size_compat_hint_popup);
- hintPopup.setOnClickListener(this);
- }
-
- @Override
- public void onClick(View v) {
- mLayout.dismissHint();
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java
deleted file mode 100644
index d75fe5173c5f..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.sizecompatui;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.ImageButton;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.wm.shell.R;
-
-/** Button to restart the size compat activity. */
-public class SizeCompatRestartButton extends FrameLayout implements View.OnClickListener,
- View.OnLongClickListener {
-
- private SizeCompatUILayout mLayout;
-
- public SizeCompatRestartButton(@NonNull Context context) {
- super(context);
- }
-
- public SizeCompatRestartButton(@NonNull Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
-
- public SizeCompatRestartButton(@NonNull Context context, @Nullable AttributeSet attrs,
- int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public SizeCompatRestartButton(@NonNull Context context, @Nullable AttributeSet attrs,
- int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- void inject(SizeCompatUILayout layout) {
- mLayout = layout;
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- final ImageButton restartButton = findViewById(R.id.size_compat_restart_button);
- restartButton.setOnClickListener(this);
- restartButton.setOnLongClickListener(this);
- }
-
- @Override
- public void onClick(View v) {
- mLayout.onRestartButtonClicked();
- }
-
- @Override
- public boolean onLongClick(View v) {
- mLayout.onRestartButtonLongClicked();
- return true;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
deleted file mode 100644
index c35b89af6c1b..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.sizecompatui;
-
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.os.Binder;
-import android.util.Log;
-import android.view.SurfaceControl;
-import android.view.View;
-import android.view.WindowManager;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.wm.shell.R;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-/**
- * Records and handles layout of size compat UI on a task with size compat activity. Helps to
- * calculate proper bounds when configuration or UI position changes.
- */
-class SizeCompatUILayout {
- private static final String TAG = "SizeCompatUILayout";
-
- final SyncTransactionQueue mSyncQueue;
- private final SizeCompatUIController.SizeCompatUICallback mCallback;
- private Context mContext;
- private Configuration mTaskConfig;
- private final int mDisplayId;
- private final int mTaskId;
- private ShellTaskOrganizer.TaskListener mTaskListener;
- private DisplayLayout mDisplayLayout;
- private final Rect mStableBounds;
- private final int mButtonWidth;
- private final int mButtonHeight;
- private final int mPopupOffsetX;
- private final int mPopupOffsetY;
-
- @VisibleForTesting
- final SizeCompatUIWindowManager mButtonWindowManager;
- @VisibleForTesting
- @Nullable
- SizeCompatUIWindowManager mHintWindowManager;
- @VisibleForTesting
- @Nullable
- SizeCompatRestartButton mButton;
- @VisibleForTesting
- @Nullable
- SizeCompatHintPopup mHint;
- @VisibleForTesting
- boolean mShouldShowHint;
-
- SizeCompatUILayout(SyncTransactionQueue syncQueue,
- SizeCompatUIController.SizeCompatUICallback callback, Context context,
- Configuration taskConfig, int taskId, ShellTaskOrganizer.TaskListener taskListener,
- DisplayLayout displayLayout, boolean hasShownHint) {
- mSyncQueue = syncQueue;
- mCallback = callback;
- mContext = context.createConfigurationContext(taskConfig);
- mTaskConfig = taskConfig;
- mDisplayId = mContext.getDisplayId();
- mTaskId = taskId;
- mTaskListener = taskListener;
- mDisplayLayout = displayLayout;
- mShouldShowHint = !hasShownHint;
- mButtonWindowManager = new SizeCompatUIWindowManager(mContext, taskConfig, this);
-
- mStableBounds = new Rect();
- mDisplayLayout.getStableBounds(mStableBounds);
-
- final Resources resources = mContext.getResources();
- mButtonWidth = resources.getDimensionPixelSize(R.dimen.size_compat_button_width);
- mButtonHeight = resources.getDimensionPixelSize(R.dimen.size_compat_button_height);
- mPopupOffsetX = (mButtonWidth / 2) - resources.getDimensionPixelSize(
- R.dimen.size_compat_hint_corner_radius) - (resources.getDimensionPixelSize(
- R.dimen.size_compat_hint_point_width) / 2);
- mPopupOffsetY = mButtonHeight;
- }
-
- /** Creates the activity restart button window. */
- void createSizeCompatButton(boolean show) {
- if (!show || mButton != null) {
- // Wait until button should be visible.
- return;
- }
- mButton = mButtonWindowManager.createSizeCompatButton();
- updateButtonSurfacePosition();
-
- if (mShouldShowHint) {
- // Only show by default for the first time.
- mShouldShowHint = false;
- createSizeCompatHint();
- }
-
- mCallback.onSizeCompatRestartButtonAppeared(mTaskId);
- }
-
- /** Creates the restart button hint window. */
- private void createSizeCompatHint() {
- if (mHint != null) {
- // Hint already shown.
- return;
- }
- mHintWindowManager = createHintWindowManager();
- mHint = mHintWindowManager.createSizeCompatHint();
- updateHintSurfacePosition();
- }
-
- @VisibleForTesting
- SizeCompatUIWindowManager createHintWindowManager() {
- return new SizeCompatUIWindowManager(mContext, mTaskConfig, this);
- }
-
- /** Dismisses the hint window. */
- void dismissHint() {
- mHint = null;
- if (mHintWindowManager != null) {
- mHintWindowManager.release();
- mHintWindowManager = null;
- }
- }
-
- /** Releases the UI windows. */
- void release() {
- dismissHint();
- mButton = null;
- mButtonWindowManager.release();
- }
-
- /** Called when size compat info changed. */
- void updateSizeCompatInfo(Configuration taskConfig,
- ShellTaskOrganizer.TaskListener taskListener, boolean show) {
- final Configuration prevTaskConfig = mTaskConfig;
- final ShellTaskOrganizer.TaskListener prevTaskListener = mTaskListener;
- mTaskConfig = taskConfig;
- mTaskListener = taskListener;
-
- // Update configuration.
- mContext = mContext.createConfigurationContext(taskConfig);
- mButtonWindowManager.setConfiguration(taskConfig);
- if (mHintWindowManager != null) {
- mHintWindowManager.setConfiguration(taskConfig);
- }
-
- if (mButton == null || prevTaskListener != taskListener) {
- // TaskListener changed, recreate the button for new surface parent.
- release();
- createSizeCompatButton(show);
- return;
- }
-
- if (!taskConfig.windowConfiguration.getBounds()
- .equals(prevTaskConfig.windowConfiguration.getBounds())) {
- // Reposition the UI surfaces.
- updateAllSurfacePositions();
- }
-
- if (taskConfig.getLayoutDirection() != prevTaskConfig.getLayoutDirection()) {
- // Update layout for RTL.
- mButton.setLayoutDirection(taskConfig.getLayoutDirection());
- updateButtonSurfacePosition();
- if (mHint != null) {
- mHint.setLayoutDirection(taskConfig.getLayoutDirection());
- updateHintSurfacePosition();
- }
- }
- }
-
- /** Called when display layout changed. */
- void updateDisplayLayout(DisplayLayout displayLayout) {
- final Rect prevStableBounds = mStableBounds;
- final Rect curStableBounds = new Rect();
- displayLayout.getStableBounds(curStableBounds);
- mDisplayLayout = displayLayout;
- if (!prevStableBounds.equals(curStableBounds)) {
- // Stable bounds changed, update UI surface positions.
- updateAllSurfacePositions();
- mStableBounds.set(curStableBounds);
- }
- }
-
- /** Called when the visibility of the UI should change. */
- void updateVisibility(boolean show) {
- if (mButton == null) {
- // Button may not have been created because it was hidden previously.
- createSizeCompatButton(show);
- return;
- }
-
- // Hide size compat UIs when IME is showing.
- final int newVisibility = show ? View.VISIBLE : View.GONE;
- if (mButton.getVisibility() != newVisibility) {
- mButton.setVisibility(newVisibility);
- }
- if (mHint != null && mHint.getVisibility() != newVisibility) {
- mHint.setVisibility(newVisibility);
- }
- }
-
- /** Gets the layout params for restart button. */
- WindowManager.LayoutParams getButtonWindowLayoutParams() {
- final WindowManager.LayoutParams winParams = new WindowManager.LayoutParams(
- // Cannot be wrap_content as this determines the actual window size
- mButtonWidth, mButtonHeight,
- TYPE_APPLICATION_OVERLAY,
- FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,
- PixelFormat.TRANSLUCENT);
- winParams.token = new Binder();
- winParams.setTitle(SizeCompatRestartButton.class.getSimpleName() + getTaskId());
- winParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
- return winParams;
- }
-
- /** Gets the layout params for hint popup. */
- WindowManager.LayoutParams getHintWindowLayoutParams(SizeCompatHintPopup hint) {
- final WindowManager.LayoutParams winParams = new WindowManager.LayoutParams(
- // Cannot be wrap_content as this determines the actual window size
- hint.getMeasuredWidth(), hint.getMeasuredHeight(),
- TYPE_APPLICATION_OVERLAY,
- FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,
- PixelFormat.TRANSLUCENT);
- winParams.token = new Binder();
- winParams.setTitle(SizeCompatHintPopup.class.getSimpleName() + getTaskId());
- winParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
- winParams.windowAnimations = android.R.style.Animation_InputMethod;
- return winParams;
- }
-
- /** Called when it is ready to be placed size compat UI surface. */
- void attachToParentSurface(SurfaceControl.Builder b) {
- mTaskListener.attachChildSurfaceToTask(mTaskId, b);
- }
-
- /** Called when the restart button is clicked. */
- void onRestartButtonClicked() {
- mCallback.onSizeCompatRestartButtonClicked(mTaskId);
- }
-
- /** Called when the restart button is long clicked. */
- void onRestartButtonLongClicked() {
- createSizeCompatHint();
- }
-
- private void updateAllSurfacePositions() {
- updateButtonSurfacePosition();
- updateHintSurfacePosition();
- }
-
- @VisibleForTesting
- void updateButtonSurfacePosition() {
- if (mButton == null || mButtonWindowManager.getSurfaceControl() == null) {
- return;
- }
- final SurfaceControl leash = mButtonWindowManager.getSurfaceControl();
-
- // Use stable bounds to prevent the button from overlapping with system bars.
- final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
- final Rect stableBounds = new Rect();
- mDisplayLayout.getStableBounds(stableBounds);
- stableBounds.intersect(taskBounds);
-
- // Position of the button in the container coordinate.
- final int positionX = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
- ? stableBounds.left - taskBounds.left
- : stableBounds.right - taskBounds.left - mButtonWidth;
- final int positionY = stableBounds.bottom - taskBounds.top - mButtonHeight;
-
- updateSurfacePosition(leash, positionX, positionY);
- }
-
- @VisibleForTesting
- void updateHintSurfacePosition() {
- if (mHint == null || mHintWindowManager == null
- || mHintWindowManager.getSurfaceControl() == null) {
- return;
- }
- final SurfaceControl leash = mHintWindowManager.getSurfaceControl();
-
- // Use stable bounds to prevent the hint from overlapping with system bars.
- final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
- final Rect stableBounds = new Rect();
- mDisplayLayout.getStableBounds(stableBounds);
- stableBounds.intersect(taskBounds);
-
- // Position of the hint in the container coordinate.
- final int positionX = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
- ? stableBounds.left - taskBounds.left + mPopupOffsetX
- : stableBounds.right - taskBounds.left - mPopupOffsetX - mHint.getMeasuredWidth();
- final int positionY =
- stableBounds.bottom - taskBounds.top - mPopupOffsetY - mHint.getMeasuredHeight();
-
- updateSurfacePosition(leash, positionX, positionY);
- }
-
- private void updateSurfacePosition(SurfaceControl leash, int positionX, int positionY) {
- mSyncQueue.runInSync(t -> {
- if (!leash.isValid()) {
- Log.w(TAG, "The leash has been released.");
- return;
- }
- t.setPosition(leash, positionX, positionY);
- // The size compat UI should be the topmost child of the Task in case there can be more
- // than one children.
- t.setLayer(leash, Integer.MAX_VALUE);
- });
- }
-
- int getDisplayId() {
- return mDisplayId;
- }
-
- int getTaskId() {
- return mTaskId;
- }
-
- private int getLayoutDirection() {
- return mContext.getResources().getConfiguration().getLayoutDirection();
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java
deleted file mode 100644
index 82f69c3e2985..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.sizecompatui;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.view.IWindow;
-import android.view.LayoutInflater;
-import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.SurfaceSession;
-import android.view.View;
-import android.view.WindowlessWindowManager;
-
-import com.android.wm.shell.R;
-
-/**
- * Holds view hierarchy of a root surface and helps to inflate {@link SizeCompatRestartButton} or
- * {@link SizeCompatHintPopup}.
- */
-class SizeCompatUIWindowManager extends WindowlessWindowManager {
-
- private Context mContext;
- private final SizeCompatUILayout mLayout;
-
- @Nullable
- private SurfaceControlViewHost mViewHost;
- @Nullable
- private SurfaceControl mLeash;
-
- SizeCompatUIWindowManager(Context context, Configuration config, SizeCompatUILayout layout) {
- super(config, null /* rootSurface */, null /* hostInputToken */);
- mContext = context;
- mLayout = layout;
- }
-
- @Override
- public void setConfiguration(Configuration configuration) {
- super.setConfiguration(configuration);
- mContext = mContext.createConfigurationContext(configuration);
- }
-
- @Override
- protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
- // Can't set position for the ViewRootImpl SC directly. Create a leash to manipulate later.
- final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
- .setContainerLayer()
- .setName("SizeCompatUILeash")
- .setHidden(false)
- .setCallsite("SizeCompatUIWindowManager#attachToParentSurface");
- mLayout.attachToParentSurface(builder);
- mLeash = builder.build();
- b.setParent(mLeash);
- }
-
- /** Inflates {@link SizeCompatRestartButton} on to the root surface. */
- SizeCompatRestartButton createSizeCompatButton() {
- if (mViewHost != null) {
- throw new IllegalStateException(
- "A UI has already been created with this window manager.");
- }
-
- mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
-
- final SizeCompatRestartButton button = (SizeCompatRestartButton)
- LayoutInflater.from(mContext).inflate(R.layout.size_compat_ui, null);
- button.inject(mLayout);
- mViewHost.setView(button, mLayout.getButtonWindowLayoutParams());
- return button;
- }
-
- /** Inflates {@link SizeCompatHintPopup} on to the root surface. */
- SizeCompatHintPopup createSizeCompatHint() {
- if (mViewHost != null) {
- throw new IllegalStateException(
- "A UI has already been created with this window manager.");
- }
-
- mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
-
- final SizeCompatHintPopup hint = (SizeCompatHintPopup)
- LayoutInflater.from(mContext).inflate(R.layout.size_compat_mode_hint, null);
- // Measure how big the hint is.
- hint.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
- hint.inject(mLayout);
- mViewHost.setView(hint, mLayout.getHintWindowLayoutParams(hint));
- return hint;
- }
-
- /** Releases the surface control and tears down the view hierarchy. */
- void release() {
- if (mViewHost != null) {
- mViewHost.release();
- mViewHost = null;
- }
-
- if (mLeash != null) {
- final SurfaceControl leash = mLeash;
- mLayout.mSyncQueue.runInSync(t -> t.remove(leash));
- mLeash = null;
- }
- }
-
- /**
- * Gets {@link SurfaceControl} of the surface holding size compat UI view. @return {@code null}
- * if not feasible.
- */
- @Nullable
- SurfaceControl getSurfaceControl() {
- return mLeash;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 05552aad2303..cf4e56e128bf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -102,6 +102,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
static final int EXIT_REASON_ROOT_TASK_VANISHED = 6;
static final int EXIT_REASON_SCREEN_LOCKED = 7;
static final int EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP = 8;
+ static final int EXIT_REASON_CHILD_TASK_ENTER_PIP = 9;
@IntDef(value = {
EXIT_REASON_UNKNOWN,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW,
@@ -112,6 +113,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
EXIT_REASON_ROOT_TASK_VANISHED,
EXIT_REASON_SCREEN_LOCKED,
EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP,
+ EXIT_REASON_CHILD_TASK_ENTER_PIP,
})
@Retention(RetentionPolicy.SOURCE)
@interface ExitReason{}
@@ -406,6 +408,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
return "APP_FINISHED";
case EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW:
return "APP_DOES_NOT_SUPPORT_MULTIWINDOW";
+ case EXIT_REASON_CHILD_TASK_ENTER_PIP:
+ return "CHILD_TASK_ENTER_PIP";
default:
return "unknown reason, reason int = " + exitReason;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index e30e6c537c93..dd538dc4602c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -35,6 +35,7 @@ import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DEVICE_FOLDED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
@@ -629,8 +630,12 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
});
mShouldUpdateRecents = false;
- mSideStage.removeAllTasks(wct, childrenToTop == mSideStage);
- mMainStage.deactivate(wct, childrenToTop == mMainStage);
+ // When the exit split-screen is caused by one of the task enters auto pip,
+ // we want the tasks to be put to bottom instead of top, otherwise it will end up
+ // a fullscreen plus a pinned task instead of pinned only at the end of the transition.
+ final boolean fromEnteringPip = exitReason == EXIT_REASON_CHILD_TASK_ENTER_PIP;
+ mSideStage.removeAllTasks(wct, !fromEnteringPip && childrenToTop == mSideStage);
+ mMainStage.deactivate(wct, !fromEnteringPip && childrenToTop == mMainStage);
mTaskOrganizer.applyTransaction(wct);
mSyncQueue.runInSync(t -> t
.setWindowCrop(mMainStage.mRootLeash, null)
@@ -660,6 +665,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
case EXIT_REASON_DRAG_DIVIDER:
// Either of the split apps have finished
case EXIT_REASON_APP_FINISHED:
+ // One of the children enters PiP
+ case EXIT_REASON_CHILD_TASK_ENTER_PIP:
return true;
default:
return false;
@@ -749,6 +756,11 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
+ private void onStageChildTaskEnterPip(StageListenerImpl stageListener, int taskId) {
+ exitSplitScreen(stageListener == mMainStageListener ? mMainStage : mSideStage,
+ EXIT_REASON_CHILD_TASK_ENTER_PIP);
+ }
+
private void updateRecentTasksSplitPair() {
if (!mShouldUpdateRecents) {
return;
@@ -1437,6 +1449,11 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
@Override
+ public void onChildTaskEnterPip(int taskId) {
+ StageCoordinator.this.onStageChildTaskEnterPip(this, taskId);
+ }
+
+ @Override
public void onRootTaskVanished() {
reset();
StageCoordinator.this.onStageRootTaskVanished(this);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index cd10b9fde444..2c853c1c474c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -20,6 +20,7 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -73,6 +74,8 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
void onChildTaskStatusChanged(int taskId, boolean present, boolean visible);
+ void onChildTaskEnterPip(int taskId);
+
void onRootTaskVanished();
void onNoLongerSupportMultiWindow();
@@ -256,6 +259,9 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
mChildrenTaskInfo.remove(taskId);
mChildrenLeashes.remove(taskId);
mCallbacks.onChildTaskStatusChanged(taskId, false /* present */, taskInfo.isVisible);
+ if (taskInfo.getWindowingMode() == WINDOWING_MODE_PINNED) {
+ mCallbacks.onChildTaskEnterPip(taskId);
+ }
if (ENABLE_SHELL_TRANSITIONS) {
// Status is managed/synchronized by the transition lifecycle.
return;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index 1fcbf14fb732..a3b98a8fc880 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -56,7 +56,7 @@ import androidx.test.filters.SmallTest;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.sizecompatui.SizeCompatUIController;
+import com.android.wm.shell.compatui.CompatUIController;
import org.junit.Before;
import org.junit.Test;
@@ -82,7 +82,7 @@ public class ShellTaskOrganizerTests {
@Mock
private Context mContext;
@Mock
- private SizeCompatUIController mSizeCompatUI;
+ private CompatUIController mCompatUI;
ShellTaskOrganizer mOrganizer;
private final SyncTransactionQueue mSyncTransactionQueue = mock(SyncTransactionQueue.class);
@@ -132,7 +132,7 @@ public class ShellTaskOrganizerTests {
.when(mTaskOrganizerController).registerTaskOrganizer(any());
} catch (RemoteException e) {}
mOrganizer = spy(new ShellTaskOrganizer(mTaskOrganizerController, mTestExecutor, mContext,
- mSizeCompatUI, Optional.empty()));
+ mCompatUI, Optional.empty()));
}
@Test
@@ -334,34 +334,34 @@ public class ShellTaskOrganizerTests {
mOrganizer.onTaskAppeared(taskInfo1, null);
// sizeCompatActivity is null if top activity is not in size compat.
- verify(mSizeCompatUI).onSizeCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId,
+ verify(mCompatUI).onCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId,
null /* taskConfig */, null /* taskListener */);
// sizeCompatActivity is non-null if top activity is in size compat.
- clearInvocations(mSizeCompatUI);
+ clearInvocations(mCompatUI);
final RunningTaskInfo taskInfo2 =
createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode());
taskInfo2.displayId = taskInfo1.displayId;
taskInfo2.topActivityInSizeCompat = true;
taskInfo2.isVisible = true;
mOrganizer.onTaskInfoChanged(taskInfo2);
- verify(mSizeCompatUI).onSizeCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId,
+ verify(mCompatUI).onCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId,
taskInfo1.configuration, taskListener);
// Not show size compat UI if task is not visible.
- clearInvocations(mSizeCompatUI);
+ clearInvocations(mCompatUI);
final RunningTaskInfo taskInfo3 =
createTaskInfo(taskInfo1.taskId, taskInfo1.getWindowingMode());
taskInfo3.displayId = taskInfo1.displayId;
taskInfo3.topActivityInSizeCompat = true;
taskInfo3.isVisible = false;
mOrganizer.onTaskInfoChanged(taskInfo3);
- verify(mSizeCompatUI).onSizeCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId,
+ verify(mCompatUI).onCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId,
null /* taskConfig */, null /* taskListener */);
- clearInvocations(mSizeCompatUI);
+ clearInvocations(mCompatUI);
mOrganizer.onTaskVanished(taskInfo1);
- verify(mSizeCompatUI).onSizeCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId,
+ verify(mCompatUI).onCompatInfoChanged(taskInfo1.displayId, taskInfo1.taskId,
null /* taskConfig */, null /* taskListener */);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index bc701d0c70bc..8bc1223cfd64 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -39,6 +39,7 @@ import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.Log;
import android.util.Pair;
import android.view.WindowManager;
@@ -913,6 +914,31 @@ public class BubbleDataTest extends ShellTestCase {
assertSelectionChangedTo(mBubbleA2);
}
+ /**
+ * - have a maxed out bubble stack & all of the bubbles have been recently accessed
+ * - bubble a notification that was posted before any of those bubbles were accessed
+ * => that bubble should be added
+ *
+ */
+ @Test
+ public void test_addOldNotifWithNewerBubbles() {
+ sendUpdatedEntryAtTime(mEntryA1, 2000);
+ sendUpdatedEntryAtTime(mEntryA2, 3000);
+ sendUpdatedEntryAtTime(mEntryA3, 4000);
+ sendUpdatedEntryAtTime(mEntryB1, 5000);
+ sendUpdatedEntryAtTime(mEntryB2, 6000);
+
+ mBubbleData.setListener(mListener);
+ sendUpdatedEntryAtTime(mEntryB3, 1000 /* postTime */, 7000 /* currentTime */);
+ verifyUpdateReceived();
+
+ // B3 is in the stack
+ assertThat(mBubbleData.getBubbleInStackWithKey(mBubbleB3.getKey())).isNotNull();
+ // A1 is the oldest so it's in the overflow
+ assertThat(mBubbleData.getOverflowBubbleWithKey(mEntryA1.getKey())).isNotNull();
+ assertOrderChangedTo(mBubbleB3, mBubbleB2, mBubbleB1, mBubbleA3, mBubbleA2);
+ }
+
private void verifyUpdateReceived() {
verify(mListener).applyUpdate(mUpdateCaptor.capture());
reset(mListener);
@@ -1014,6 +1040,12 @@ public class BubbleDataTest extends ShellTestCase {
}
private void sendUpdatedEntryAtTime(BubbleEntry entry, long postTime) {
+ setCurrentTime(postTime);
+ sendUpdatedEntryAtTime(entry, postTime, true /* isTextChanged */);
+ }
+
+ private void sendUpdatedEntryAtTime(BubbleEntry entry, long postTime, long currentTime) {
+ setCurrentTime(currentTime);
sendUpdatedEntryAtTime(entry, postTime, true /* isTextChanged */);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index 877b19223bf6..f622edb7f134 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.sizecompatui;
+package com.android.wm.shell.compatui;
import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
@@ -56,18 +56,18 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
- * Tests for {@link SizeCompatUIController}.
+ * Tests for {@link CompatUIController}.
*
* Build/Install/Run:
- * atest WMShellUnitTests:SizeCompatUIControllerTest
+ * atest WMShellUnitTests:CompatUIControllerTest
*/
@RunWith(AndroidTestingRunner.class)
@SmallTest
-public class SizeCompatUIControllerTest extends ShellTestCase {
+public class CompatUIControllerTest extends ShellTestCase {
private static final int DISPLAY_ID = 0;
private static final int TASK_ID = 12;
- private SizeCompatUIController mController;
+ private CompatUIController mController;
private @Mock DisplayController mMockDisplayController;
private @Mock DisplayInsetsController mMockDisplayInsetsController;
private @Mock DisplayLayout mMockDisplayLayout;
@@ -75,7 +75,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
private @Mock ShellTaskOrganizer.TaskListener mMockTaskListener;
private @Mock SyncTransactionQueue mMockSyncQueue;
private @Mock ShellExecutor mMockExecutor;
- private @Mock SizeCompatUILayout mMockLayout;
+ private @Mock CompatUIWindowManager mMockLayout;
@Captor
ArgumentCaptor<OnInsetsChangedListener> mOnInsetsChangedListenerCaptor;
@@ -87,10 +87,10 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
doReturn(mMockDisplayLayout).when(mMockDisplayController).getDisplayLayout(anyInt());
doReturn(DISPLAY_ID).when(mMockLayout).getDisplayId();
doReturn(TASK_ID).when(mMockLayout).getTaskId();
- mController = new SizeCompatUIController(mContext, mMockDisplayController,
+ mController = new CompatUIController(mContext, mMockDisplayController,
mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor) {
@Override
- SizeCompatUILayout createLayout(Context context, int displayId, int taskId,
+ CompatUIWindowManager createLayout(Context context, int displayId, int taskId,
Configuration taskConfig, ShellTaskOrganizer.TaskListener taskListener) {
return mMockLayout;
}
@@ -105,24 +105,24 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
}
@Test
- public void testOnSizeCompatInfoChanged() {
+ public void testOnCompatInfoChanged() {
final Configuration taskConfig = new Configuration();
// Verify that the restart button is added with non-null size compat info.
- mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
+ mController.onCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
verify(mController).createLayout(any(), eq(DISPLAY_ID), eq(TASK_ID), eq(taskConfig),
eq(mMockTaskListener));
// Verify that the restart button is updated with non-null new size compat info.
final Configuration newTaskConfig = new Configuration();
- mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, newTaskConfig, mMockTaskListener);
+ mController.onCompatInfoChanged(DISPLAY_ID, TASK_ID, newTaskConfig, mMockTaskListener);
- verify(mMockLayout).updateSizeCompatInfo(taskConfig, mMockTaskListener,
+ verify(mMockLayout).updateCompatInfo(taskConfig, mMockTaskListener,
true /* show */);
// Verify that the restart button is removed with null size compat info.
- mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, null, mMockTaskListener);
+ mController.onCompatInfoChanged(DISPLAY_ID, TASK_ID, null, mMockTaskListener);
verify(mMockLayout).release();
}
@@ -140,7 +140,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
public void testOnDisplayRemoved() {
mController.onDisplayAdded(DISPLAY_ID);
final Configuration taskConfig = new Configuration();
- mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
+ mController.onCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
mMockTaskListener);
mController.onDisplayRemoved(DISPLAY_ID + 1);
@@ -158,7 +158,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
@Test
public void testOnDisplayConfigurationChanged() {
final Configuration taskConfig = new Configuration();
- mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
+ mController.onCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
mMockTaskListener);
final Configuration newTaskConfig = new Configuration();
@@ -175,7 +175,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
public void testInsetsChanged() {
mController.onDisplayAdded(DISPLAY_ID);
final Configuration taskConfig = new Configuration();
- mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
+ mController.onCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
mMockTaskListener);
InsetsState insetsState = new InsetsState();
InsetsSource insetsSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR);
@@ -197,7 +197,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
@Test
public void testChangeButtonVisibilityOnImeShowHide() {
final Configuration taskConfig = new Configuration();
- mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
+ mController.onCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
// Verify that the restart button is hidden after IME is showing.
mController.onImeVisibilityChanged(DISPLAY_ID, true /* isShowing */);
@@ -205,9 +205,9 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
verify(mMockLayout).updateVisibility(false);
// Verify button remains hidden while IME is showing.
- mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
+ mController.onCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
- verify(mMockLayout).updateSizeCompatInfo(taskConfig, mMockTaskListener,
+ verify(mMockLayout).updateCompatInfo(taskConfig, mMockTaskListener,
false /* show */);
// Verify button is shown after IME is hidden.
@@ -219,7 +219,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
@Test
public void testChangeButtonVisibilityOnKeyguardOccludedChanged() {
final Configuration taskConfig = new Configuration();
- mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
+ mController.onCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
// Verify that the restart button is hidden after keyguard becomes occluded.
mController.onKeyguardOccludedChanged(true);
@@ -227,9 +227,9 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
verify(mMockLayout).updateVisibility(false);
// Verify button remains hidden while keyguard is occluded.
- mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
+ mController.onCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
- verify(mMockLayout).updateSizeCompatInfo(taskConfig, mMockTaskListener,
+ verify(mMockLayout).updateCompatInfo(taskConfig, mMockTaskListener,
false /* show */);
// Verify button is shown after keyguard becomes not occluded.
@@ -241,7 +241,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
@Test
public void testButtonRemainsHiddenOnKeyguardOccludedFalseWhenImeIsShowing() {
final Configuration taskConfig = new Configuration();
- mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
+ mController.onCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
mController.onImeVisibilityChanged(DISPLAY_ID, true /* isShowing */);
mController.onKeyguardOccludedChanged(true);
@@ -264,7 +264,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
@Test
public void testButtonRemainsHiddenOnImeHideWhenKeyguardIsOccluded() {
final Configuration taskConfig = new Configuration();
- mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
+ mController.onCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig, mMockTaskListener);
mController.onImeVisibilityChanged(DISPLAY_ID, true /* isShowing */);
mController.onKeyguardOccludedChanged(true);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
index a20a5e9e8d91..2c3987bc358d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
@@ -14,17 +14,20 @@
* limitations under the License.
*/
-package com.android.wm.shell.sizecompatui;
+package com.android.wm.shell.compatui;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import android.content.res.Configuration;
import android.testing.AndroidTestingRunner;
import android.view.LayoutInflater;
+import android.view.SurfaceControlViewHost;
import android.widget.ImageButton;
+import android.widget.LinearLayout;
import androidx.test.filters.SmallTest;
@@ -41,55 +44,68 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
- * Tests for {@link SizeCompatRestartButton}.
+ * Tests for {@link CompatUILayout}.
*
* Build/Install/Run:
- * atest WMShellUnitTests:SizeCompatRestartButtonTest
+ * atest WMShellUnitTests:CompatUILayoutTest
*/
@RunWith(AndroidTestingRunner.class)
@SmallTest
-public class SizeCompatRestartButtonTest extends ShellTestCase {
+public class CompatUILayoutTest extends ShellTestCase {
private static final int TASK_ID = 1;
@Mock private SyncTransactionQueue mSyncTransactionQueue;
- @Mock private SizeCompatUIController.SizeCompatUICallback mCallback;
+ @Mock private CompatUIController.CompatUICallback mCallback;
@Mock private ShellTaskOrganizer.TaskListener mTaskListener;
- @Mock private DisplayLayout mDisplayLayout;
+ @Mock private SurfaceControlViewHost mViewHost;
- private SizeCompatUILayout mLayout;
- private SizeCompatRestartButton mButton;
+ private CompatUIWindowManager mWindowManager;
+ private CompatUILayout mCompatUILayout;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mCallback, mContext,
- new Configuration(), TASK_ID, mTaskListener, mDisplayLayout,
+ mWindowManager = new CompatUIWindowManager(mContext, new Configuration(),
+ mSyncTransactionQueue, mCallback, TASK_ID, mTaskListener, new DisplayLayout(),
false /* hasShownHint */);
- mButton = (SizeCompatRestartButton)
- LayoutInflater.from(mContext).inflate(R.layout.size_compat_ui, null);
- mButton.inject(mLayout);
- spyOn(mLayout);
+ mCompatUILayout = (CompatUILayout)
+ LayoutInflater.from(mContext).inflate(R.layout.compat_ui_layout, null);
+ mCompatUILayout.inject(mWindowManager);
+
+ spyOn(mWindowManager);
+ spyOn(mCompatUILayout);
+ doReturn(mViewHost).when(mWindowManager).createSurfaceViewHost();
}
@Test
- public void testOnClick() {
- final ImageButton button = mButton.findViewById(R.id.size_compat_restart_button);
+ public void testOnClickForRestartButton() {
+ final ImageButton button = mCompatUILayout.findViewById(R.id.size_compat_restart_button);
button.performClick();
- verify(mLayout).onRestartButtonClicked();
+ verify(mWindowManager).onRestartButtonClicked();
+ doReturn(mCompatUILayout).when(mWindowManager).inflateCompatUILayout();
verify(mCallback).onSizeCompatRestartButtonClicked(TASK_ID);
}
@Test
- public void testOnLongClick() {
- doNothing().when(mLayout).onRestartButtonLongClicked();
+ public void testOnLongClickForRestartButton() {
+ doNothing().when(mWindowManager).onRestartButtonLongClicked();
- final ImageButton button = mButton.findViewById(R.id.size_compat_restart_button);
+ final ImageButton button = mCompatUILayout.findViewById(R.id.size_compat_restart_button);
button.performLongClick();
- verify(mLayout).onRestartButtonLongClicked();
+ verify(mWindowManager).onRestartButtonLongClicked();
+ }
+
+ @Test
+ public void testOnClickForSizeCompatHint() {
+ mWindowManager.createLayout(true /* show */);
+ final LinearLayout sizeCompatHint = mCompatUILayout.findViewById(R.id.size_compat_hint);
+ sizeCompatHint.performClick();
+
+ verify(mCompatUILayout).setSizeCompatHintVisibility(/* show= */ false);
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
new file mode 100644
index 000000000000..d5dcf2e11a46
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui;
+
+import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.testing.AndroidTestingRunner;
+import android.view.DisplayInfo;
+import android.view.InsetsSource;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.SyncTransactionQueue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link CompatUIWindowManager}.
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:CompatUIWindowManagerTest
+ */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class CompatUIWindowManagerTest extends ShellTestCase {
+
+ private static final int TASK_ID = 1;
+
+ @Mock private SyncTransactionQueue mSyncTransactionQueue;
+ @Mock private CompatUIController.CompatUICallback mCallback;
+ @Mock private ShellTaskOrganizer.TaskListener mTaskListener;
+ @Mock private CompatUILayout mCompatUILayout;
+ @Mock private SurfaceControlViewHost mViewHost;
+ private Configuration mTaskConfig;
+
+ private CompatUIWindowManager mWindowManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mTaskConfig = new Configuration();
+
+ mWindowManager = new CompatUIWindowManager(mContext, new Configuration(),
+ mSyncTransactionQueue, mCallback, TASK_ID, mTaskListener, new DisplayLayout(),
+ false /* hasShownHint */);
+
+ spyOn(mWindowManager);
+ doReturn(mCompatUILayout).when(mWindowManager).inflateCompatUILayout();
+ doReturn(mViewHost).when(mWindowManager).createSurfaceViewHost();
+ }
+
+ @Test
+ public void testCreateSizeCompatButton() {
+ // Not create layout if show is false.
+ mWindowManager.createLayout(false /* show */);
+
+ verify(mWindowManager, never()).inflateCompatUILayout();
+
+ // Not create hint popup.
+ mWindowManager.mShouldShowHint = false;
+ mWindowManager.createLayout(true /* show */);
+
+ verify(mWindowManager).inflateCompatUILayout();
+ verify(mCompatUILayout).setSizeCompatHintVisibility(false /* show */);
+
+ // Create hint popup.
+ mWindowManager.release();
+ mWindowManager.mShouldShowHint = true;
+ mWindowManager.createLayout(true /* show */);
+
+ verify(mWindowManager, times(2)).inflateCompatUILayout();
+ assertNotNull(mCompatUILayout);
+ verify(mCompatUILayout).setSizeCompatHintVisibility(true /* show */);
+ assertFalse(mWindowManager.mShouldShowHint);
+ }
+
+ @Test
+ public void testRelease() {
+ mWindowManager.createLayout(true /* show */);
+
+ verify(mWindowManager).inflateCompatUILayout();
+
+ mWindowManager.release();
+
+ verify(mViewHost).release();
+ }
+
+ @Test
+ public void testUpdateCompatInfo() {
+ mWindowManager.createLayout(true /* show */);
+
+ // No diff
+ clearInvocations(mWindowManager);
+ mWindowManager.updateCompatInfo(mTaskConfig, mTaskListener, true /* show */);
+
+ verify(mWindowManager, never()).updateSurfacePosition();
+ verify(mWindowManager, never()).release();
+ verify(mWindowManager, never()).createLayout(anyBoolean());
+
+ // Change task listener, recreate button.
+ clearInvocations(mWindowManager);
+ final ShellTaskOrganizer.TaskListener newTaskListener = mock(
+ ShellTaskOrganizer.TaskListener.class);
+ mWindowManager.updateCompatInfo(mTaskConfig, newTaskListener,
+ true /* show */);
+
+ verify(mWindowManager).release();
+ verify(mWindowManager).createLayout(anyBoolean());
+
+ // Change task bounds, update position.
+ clearInvocations(mWindowManager);
+ final Configuration newTaskConfiguration = new Configuration();
+ newTaskConfiguration.windowConfiguration.setBounds(new Rect(0, 1000, 0, 2000));
+ mWindowManager.updateCompatInfo(newTaskConfiguration, newTaskListener,
+ true /* show */);
+
+ verify(mWindowManager).updateSurfacePosition();
+ }
+
+ @Test
+ public void testUpdateDisplayLayout() {
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.logicalWidth = 1000;
+ displayInfo.logicalHeight = 2000;
+ final DisplayLayout displayLayout1 = new DisplayLayout(displayInfo,
+ mContext.getResources(), /* hasNavigationBar= */ false, /* hasStatusBar= */ false);
+
+ mWindowManager.updateDisplayLayout(displayLayout1);
+ verify(mWindowManager).updateSurfacePosition();
+
+ // No update if the display bounds is the same.
+ clearInvocations(mWindowManager);
+ final DisplayLayout displayLayout2 = new DisplayLayout(displayInfo,
+ mContext.getResources(), /* hasNavigationBar= */ false, /* hasStatusBar= */ false);
+ mWindowManager.updateDisplayLayout(displayLayout2);
+ verify(mWindowManager, never()).updateSurfacePosition();
+ }
+
+ @Test
+ public void testUpdateDisplayLayoutInsets() {
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.logicalWidth = 1000;
+ displayInfo.logicalHeight = 2000;
+ final DisplayLayout displayLayout = new DisplayLayout(displayInfo,
+ mContext.getResources(), /* hasNavigationBar= */ true, /* hasStatusBar= */ false);
+
+ mWindowManager.updateDisplayLayout(displayLayout);
+ verify(mWindowManager).updateSurfacePosition();
+
+ // Update if the insets change on the existing display layout
+ clearInvocations(mWindowManager);
+ InsetsState insetsState = new InsetsState();
+ InsetsSource insetsSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR);
+ insetsSource.setFrame(0, 0, 1000, 1000);
+ insetsState.addSource(insetsSource);
+ displayLayout.setInsets(mContext.getResources(), insetsState);
+ mWindowManager.updateDisplayLayout(displayLayout);
+ verify(mWindowManager).updateSurfacePosition();
+ }
+
+ @Test
+ public void testUpdateVisibility() {
+ // Create button if it is not created.
+ mWindowManager.mCompatUILayout = null;
+ mWindowManager.updateVisibility(true /* show */);
+
+ verify(mWindowManager).createLayout(true /* show */);
+
+ // Hide button.
+ clearInvocations(mWindowManager);
+ doReturn(View.VISIBLE).when(mCompatUILayout).getVisibility();
+ mWindowManager.updateVisibility(false /* show */);
+
+ verify(mWindowManager, never()).createLayout(anyBoolean());
+ verify(mCompatUILayout).setVisibility(View.GONE);
+
+ // Show button.
+ doReturn(View.GONE).when(mCompatUILayout).getVisibility();
+ mWindowManager.updateVisibility(true /* show */);
+
+ verify(mWindowManager, never()).createLayout(anyBoolean());
+ verify(mCompatUILayout).setVisibility(View.VISIBLE);
+ }
+
+ @Test
+ public void testAttachToParentSurface() {
+ final SurfaceControl.Builder b = new SurfaceControl.Builder();
+ mWindowManager.attachToParentSurface(b);
+
+ verify(mTaskListener).attachChildSurfaceToTask(TASK_ID, b);
+ }
+
+ @Test
+ public void testOnRestartButtonClicked() {
+ mWindowManager.onRestartButtonClicked();
+
+ verify(mCallback).onSizeCompatRestartButtonClicked(TASK_ID);
+ }
+
+ @Test
+ public void testOnRestartButtonLongClicked_showHint() {
+ // Not create hint popup.
+ mWindowManager.mShouldShowHint = false;
+ mWindowManager.createLayout(true /* show */);
+
+ verify(mWindowManager).inflateCompatUILayout();
+ verify(mCompatUILayout).setSizeCompatHintVisibility(false /* show */);
+
+ mWindowManager.onRestartButtonLongClicked();
+
+ verify(mCompatUILayout).setSizeCompatHintVisibility(true /* show */);
+ }
+
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java
deleted file mode 100644
index 3a14a336190d..000000000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.sizecompatui;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.verify;
-
-import android.content.res.Configuration;
-import android.testing.AndroidTestingRunner;
-import android.view.LayoutInflater;
-import android.widget.LinearLayout;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.R;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for {@link SizeCompatHintPopup}.
- *
- * Build/Install/Run:
- * atest WMShellUnitTests:SizeCompatHintPopupTest
- */
-@RunWith(AndroidTestingRunner.class)
-@SmallTest
-public class SizeCompatHintPopupTest extends ShellTestCase {
-
- @Mock private SyncTransactionQueue mSyncTransactionQueue;
- @Mock private SizeCompatUIController.SizeCompatUICallback mCallback;
- @Mock private ShellTaskOrganizer.TaskListener mTaskListener;
- @Mock private DisplayLayout mDisplayLayout;
-
- private SizeCompatUILayout mLayout;
- private SizeCompatHintPopup mHint;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- final int taskId = 1;
- mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mCallback, mContext,
- new Configuration(), taskId, mTaskListener, mDisplayLayout,
- false /* hasShownHint */);
- mHint = (SizeCompatHintPopup)
- LayoutInflater.from(mContext).inflate(R.layout.size_compat_mode_hint, null);
- mHint.inject(mLayout);
-
- spyOn(mLayout);
- }
-
- @Test
- public void testOnClick() {
- doNothing().when(mLayout).dismissHint();
-
- final LinearLayout hintPopup = mHint.findViewById(R.id.size_compat_hint_popup);
- hintPopup.performClick();
-
- verify(mLayout).dismissHint();
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java
deleted file mode 100644
index eb9305b2e995..000000000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.sizecompatui;
-
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.testing.AndroidTestingRunner;
-import android.view.DisplayInfo;
-import android.view.InsetsSource;
-import android.view.InsetsState;
-import android.view.SurfaceControl;
-import android.view.View;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for {@link SizeCompatUILayout}.
- *
- * Build/Install/Run:
- * atest WMShellUnitTests:SizeCompatUILayoutTest
- */
-@RunWith(AndroidTestingRunner.class)
-@SmallTest
-public class SizeCompatUILayoutTest extends ShellTestCase {
-
- private static final int TASK_ID = 1;
-
- @Mock private SyncTransactionQueue mSyncTransactionQueue;
- @Mock private SizeCompatUIController.SizeCompatUICallback mCallback;
- @Mock private ShellTaskOrganizer.TaskListener mTaskListener;
- @Mock private DisplayLayout mDisplayLayout;
- @Mock private SizeCompatRestartButton mButton;
- @Mock private SizeCompatHintPopup mHint;
- private Configuration mTaskConfig;
-
- private SizeCompatUILayout mLayout;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mTaskConfig = new Configuration();
-
- mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mCallback, mContext,
- new Configuration(), TASK_ID, mTaskListener, new DisplayLayout(),
- false /* hasShownHint */);
-
- spyOn(mLayout);
- spyOn(mLayout.mButtonWindowManager);
- doReturn(mButton).when(mLayout.mButtonWindowManager).createSizeCompatButton();
-
- final SizeCompatUIWindowManager hintWindowManager = mLayout.createHintWindowManager();
- spyOn(hintWindowManager);
- doReturn(mHint).when(hintWindowManager).createSizeCompatHint();
- doReturn(hintWindowManager).when(mLayout).createHintWindowManager();
- }
-
- @Test
- public void testCreateSizeCompatButton() {
- // Not create button if show is false.
- mLayout.createSizeCompatButton(false /* show */);
-
- verify(mLayout.mButtonWindowManager, never()).createSizeCompatButton();
- assertNull(mLayout.mButton);
- assertNull(mLayout.mHintWindowManager);
- assertNull(mLayout.mHint);
-
- // Not create hint popup.
- mLayout.mShouldShowHint = false;
- mLayout.createSizeCompatButton(true /* show */);
-
- verify(mLayout.mButtonWindowManager).createSizeCompatButton();
- assertNotNull(mLayout.mButton);
- assertNull(mLayout.mHintWindowManager);
- assertNull(mLayout.mHint);
-
- // Create hint popup.
- mLayout.release();
- mLayout.mShouldShowHint = true;
- mLayout.createSizeCompatButton(true /* show */);
-
- verify(mLayout.mButtonWindowManager, times(2)).createSizeCompatButton();
- assertNotNull(mLayout.mButton);
- assertNotNull(mLayout.mHintWindowManager);
- verify(mLayout.mHintWindowManager).createSizeCompatHint();
- assertNotNull(mLayout.mHint);
- assertFalse(mLayout.mShouldShowHint);
- }
-
- @Test
- public void testRelease() {
- mLayout.createSizeCompatButton(true /* show */);
- final SizeCompatUIWindowManager hintWindowManager = mLayout.mHintWindowManager;
-
- mLayout.release();
-
- assertNull(mLayout.mButton);
- assertNull(mLayout.mHint);
- verify(hintWindowManager).release();
- assertNull(mLayout.mHintWindowManager);
- verify(mLayout.mButtonWindowManager).release();
- }
-
- @Test
- public void testUpdateSizeCompatInfo() {
- mLayout.createSizeCompatButton(true /* show */);
-
- // No diff
- clearInvocations(mLayout);
- mLayout.updateSizeCompatInfo(mTaskConfig, mTaskListener, true /* show */);
-
- verify(mLayout, never()).updateButtonSurfacePosition();
- verify(mLayout, never()).release();
- verify(mLayout, never()).createSizeCompatButton(anyBoolean());
-
- // Change task listener, recreate button.
- clearInvocations(mLayout);
- final ShellTaskOrganizer.TaskListener newTaskListener = mock(
- ShellTaskOrganizer.TaskListener.class);
- mLayout.updateSizeCompatInfo(mTaskConfig, newTaskListener,
- true /* show */);
-
- verify(mLayout).release();
- verify(mLayout).createSizeCompatButton(anyBoolean());
-
- // Change task bounds, update position.
- clearInvocations(mLayout);
- final Configuration newTaskConfiguration = new Configuration();
- newTaskConfiguration.windowConfiguration.setBounds(new Rect(0, 1000, 0, 2000));
- mLayout.updateSizeCompatInfo(newTaskConfiguration, newTaskListener,
- true /* show */);
-
- verify(mLayout).updateButtonSurfacePosition();
- verify(mLayout).updateHintSurfacePosition();
- }
-
- @Test
- public void testUpdateDisplayLayout() {
- final DisplayInfo displayInfo = new DisplayInfo();
- displayInfo.logicalWidth = 1000;
- displayInfo.logicalHeight = 2000;
- final DisplayLayout displayLayout1 = new DisplayLayout(displayInfo,
- mContext.getResources(), /* hasNavigationBar= */ false, /* hasStatusBar= */ false);
-
- mLayout.updateDisplayLayout(displayLayout1);
- verify(mLayout).updateButtonSurfacePosition();
- verify(mLayout).updateHintSurfacePosition();
-
- // No update if the display bounds is the same.
- clearInvocations(mLayout);
- final DisplayLayout displayLayout2 = new DisplayLayout(displayInfo,
- mContext.getResources(), /* hasNavigationBar= */ false, /* hasStatusBar= */ false);
- mLayout.updateDisplayLayout(displayLayout2);
- verify(mLayout, never()).updateButtonSurfacePosition();
- verify(mLayout, never()).updateHintSurfacePosition();
- }
-
- @Test
- public void testUpdateDisplayLayoutInsets() {
- final DisplayInfo displayInfo = new DisplayInfo();
- displayInfo.logicalWidth = 1000;
- displayInfo.logicalHeight = 2000;
- final DisplayLayout displayLayout = new DisplayLayout(displayInfo,
- mContext.getResources(), /* hasNavigationBar= */ true, /* hasStatusBar= */ false);
-
- mLayout.updateDisplayLayout(displayLayout);
- verify(mLayout).updateButtonSurfacePosition();
- verify(mLayout).updateHintSurfacePosition();
-
- // Update if the insets change on the existing display layout
- clearInvocations(mLayout);
- InsetsState insetsState = new InsetsState();
- InsetsSource insetsSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR);
- insetsSource.setFrame(0, 0, 1000, 1000);
- insetsState.addSource(insetsSource);
- displayLayout.setInsets(mContext.getResources(), insetsState);
- mLayout.updateDisplayLayout(displayLayout);
- verify(mLayout).updateButtonSurfacePosition();
- verify(mLayout).updateHintSurfacePosition();
- }
-
- @Test
- public void testUpdateVisibility() {
- // Create button if it is not created.
- mLayout.mButton = null;
- mLayout.updateVisibility(true /* show */);
-
- verify(mLayout).createSizeCompatButton(true /* show */);
-
- // Hide button.
- clearInvocations(mLayout);
- doReturn(View.VISIBLE).when(mButton).getVisibility();
- mLayout.updateVisibility(false /* show */);
-
- verify(mLayout, never()).createSizeCompatButton(anyBoolean());
- verify(mButton).setVisibility(View.GONE);
-
- // Show button.
- doReturn(View.GONE).when(mButton).getVisibility();
- mLayout.updateVisibility(true /* show */);
-
- verify(mLayout, never()).createSizeCompatButton(anyBoolean());
- verify(mButton).setVisibility(View.VISIBLE);
- }
-
- @Test
- public void testAttachToParentSurface() {
- final SurfaceControl.Builder b = new SurfaceControl.Builder();
- mLayout.attachToParentSurface(b);
-
- verify(mTaskListener).attachChildSurfaceToTask(TASK_ID, b);
- }
-
- @Test
- public void testOnRestartButtonClicked() {
- mLayout.onRestartButtonClicked();
-
- verify(mCallback).onSizeCompatRestartButtonClicked(TASK_ID);
- }
-
- @Test
- public void testOnRestartButtonLongClicked_showHint() {
- mLayout.dismissHint();
-
- assertNull(mLayout.mHint);
-
- mLayout.onRestartButtonLongClicked();
-
- assertNotNull(mLayout.mHint);
- }
-
- @Test
- public void testDismissHint() {
- mLayout.onRestartButtonLongClicked();
- final SizeCompatUIWindowManager hintWindowManager = mLayout.mHintWindowManager;
- assertNotNull(mLayout.mHint);
- assertNotNull(hintWindowManager);
-
- mLayout.dismissHint();
-
- assertNull(mLayout.mHint);
- assertNull(mLayout.mHintWindowManager);
- verify(hintWindowManager).release();
- }
-}
diff --git a/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java b/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
index 36c2bda8b03a..7f17d26b156a 100644
--- a/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
+++ b/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
@@ -18,7 +18,6 @@ package com.android.settingslib.activityembedding;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ResolveInfo;
import com.android.settingslib.utils.BuildCompatUtils;
@@ -37,11 +36,10 @@ public class ActivityEmbeddingUtils {
if (BuildCompatUtils.isAtLeastS()) {
final Intent intent = new Intent(ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY);
intent.setPackage(PACKAGE_NAME_SETTINGS);
- final ResolveInfo resolveInfo =
- context.getPackageManager().resolveActivity(intent, 0 /* flags */);
- return resolveInfo != null
- && resolveInfo.activityInfo != null
- && resolveInfo.activityInfo.enabled;
+ final boolean isEmbeddingActivityEnabled =
+ intent.resolveActivity(context.getPackageManager()) != null;
+
+ return isEmbeddingActivityEnabled;
}
return false;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
index 8b17be1e8ec9..dee68948a16e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
@@ -85,6 +85,7 @@ public class EnableZenModeDialog {
@VisibleForTesting
protected Context mContext;
private final int mThemeResId;
+ private final boolean mCancelIsNeutral;
@VisibleForTesting
protected TextView mZenAlarmWarning;
@VisibleForTesting
@@ -101,8 +102,13 @@ public class EnableZenModeDialog {
}
public EnableZenModeDialog(Context context, int themeResId) {
+ this(context, themeResId, false /* cancelIsNeutral */);
+ }
+
+ public EnableZenModeDialog(Context context, int themeResId, boolean cancelIsNeutral) {
mContext = context;
mThemeResId = themeResId;
+ mCancelIsNeutral = cancelIsNeutral;
}
public AlertDialog createDialog() {
@@ -115,7 +121,6 @@ public class EnableZenModeDialog {
final AlertDialog.Builder builder = new AlertDialog.Builder(mContext, mThemeResId)
.setTitle(R.string.zen_mode_settings_turn_on_dialog_title)
- .setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.zen_mode_enable_dialog_turn_on,
new DialogInterface.OnClickListener() {
@Override
@@ -145,6 +150,12 @@ public class EnableZenModeDialog {
}
});
+ if (mCancelIsNeutral) {
+ builder.setNeutralButton(R.string.cancel, null);
+ } else {
+ builder.setNegativeButton(R.string.cancel, null);
+ }
+
View contentView = getContentView();
bindConditions(forever());
builder.setView(contentView);
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_unlocked_aod.xml b/packages/SystemUI/res-keyguard/drawable/ic_unlocked_aod.xml
new file mode 100644
index 000000000000..230a25628c40
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/ic_unlocked_aod.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="65dp" android:width="46dp" android:viewportHeight="65" android:viewportWidth="46">
+ <group android:name="_R_G_L_2_G" android:translateX="23" android:translateY="32.125">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="#FF000000"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M0 6.13 C0.97,6.13 1.75,5.34 1.75,4.38 C1.75,3.41 0.97,2.63 0,2.63 C-0.97,2.63 -1.75,3.41 -1.75,4.38 C-1.75,5.34 -0.97,6.13 0,6.13c " />
+ </group>
+ <group android:name="_R_G_L_1_G" android:translateX="23" android:translateY="32.125">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:strokeColor="#FF000000"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="1.5"
+ android:strokeAlpha="1"
+ android:pathData=" M7.88 -0.62 C7.88,-0.62 7.88,9.38 7.88,9.38 C7.88,10.48 6.98,11.38 5.88,11.38 C5.88,11.38 -5.87,11.38 -5.87,11.38 C-6.98,11.38 -7.87,10.48 -7.87,9.38 C-7.87,9.38 -7.87,-0.62 -7.87,-0.62 C-7.87,-1.73 -6.98,-2.62 -5.87,-2.62 C-5.87,-2.62 5.88,-2.62 5.88,-2.62 C6.98,-2.62 7.88,-1.73 7.88,-0.62c " />
+ </group>
+ <group android:name="_R_G_L_0_G" android:translateX="14" android:translateY="13.5">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:strokeColor="#FF000000"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="1.5"
+ android:strokeAlpha="1"
+ android:pathData=" M21.25 14.88 C21.25,14.88 21.25,10.74 21.25,10.74 C21.25,8.59 19.5,7.29 17.44,7.21 C15.24,7.13 13.5,8.47 13.5,10.62 C13.5,10.62 13.5,15.75 13.5,15.75 " />
+ </group>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml b/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml
index c58e2e3266d0..b3987f1aeeda 100644
--- a/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml
+++ b/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml
@@ -50,6 +50,11 @@
android:state_first="true"
android:state_single="true"
android:drawable="@drawable/ic_lock_aod" />
+ <item
+ android:id="@+id/unlocked_aod"
+ android:state_last="true"
+ android:state_single="true"
+ android:drawable="@drawable/ic_unlocked_aod" />
<item
android:id="@+id/no_icon"
@@ -79,4 +84,19 @@
android:fromId="@id/locked"
android:toId="@id/locked_aod"
android:drawable="@drawable/lock_ls_to_aod" />
+
+ <transition
+ android:fromId="@id/unlocked_aod"
+ android:toId="@id/unlocked"
+ android:drawable="@drawable/unlocked_aod_to_ls" />
+
+ <transition
+ android:fromId="@id/unlocked"
+ android:toId="@id/unlocked_aod"
+ android:drawable="@drawable/unlocked_ls_to_aod" />
+
+ <transition
+ android:fromId="@id/unlocked"
+ android:toId="@id/locked_aod"
+ android:drawable="@drawable/unlocked_to_aod_lock" />
</animated-selector>
diff --git a/packages/SystemUI/res-keyguard/drawable/unlocked_aod_to_ls.xml b/packages/SystemUI/res-keyguard/drawable/unlocked_aod_to_ls.xml
new file mode 100644
index 000000000000..3b59ba8815b8
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/unlocked_aod_to_ls.xml
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <aapt:attr name="android:drawable">
+ <vector android:height="65dp" android:width="46dp" android:viewportHeight="65" android:viewportWidth="46">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_2_G" android:translateX="23" android:translateY="32.125">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="#FF000000"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M0 6.13 C0.97,6.13 1.75,5.34 1.75,4.38 C1.75,3.41 0.97,2.63 0,2.63 C-0.97,2.63 -1.75,3.41 -1.75,4.38 C-1.75,5.34 -0.97,6.13 0,6.13c " />
+ </group>
+ <group android:name="_R_G_L_1_G" android:translateX="23" android:translateY="32.125">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:strokeColor="#FF000000"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="1.5"
+ android:strokeAlpha="1"
+ android:pathData=" M7.88 -0.62 C7.88,-0.62 7.88,9.38 7.88,9.38 C7.88,10.48 6.98,11.38 5.88,11.38 C5.88,11.38 -5.87,11.38 -5.87,11.38 C-6.98,11.38 -7.87,10.48 -7.87,9.38 C-7.87,9.38 -7.87,-0.62 -7.87,-0.62 C-7.87,-1.73 -6.98,-2.62 -5.87,-2.62 C-5.87,-2.62 5.88,-2.62 5.88,-2.62 C6.98,-2.62 7.88,-1.73 7.88,-0.62c " />
+ </group>
+ <group android:name="_R_G_L_0_G" android:translateX="14" android:translateY="13.5">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:strokeColor="#FF000000"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="1.5"
+ android:strokeAlpha="1"
+ android:pathData=" M21.25 14.88 C21.25,14.88 21.25,10.74 21.25,10.74 C21.25,8.59 19.5,7.29 17.44,7.21 C15.24,7.13 13.5,8.47 13.5,10.62 C13.5,10.62 13.5,15.75 13.5,15.75 " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="333" android:startOffset="0" android:valueFrom="M0 6.13 C0.97,6.13 1.75,5.34 1.75,4.38 C1.75,3.41 0.97,2.63 0,2.63 C-0.97,2.63 -1.75,3.41 -1.75,4.38 C-1.75,5.34 -0.97,6.13 0,6.13c " android:valueTo="M-0.09 8.63 C1.2,8.63 2.25,7.57 2.25,6.28 C2.25,4.99 1.2,3.94 -0.09,3.94 C-1.39,3.94 -2.44,4.99 -2.44,6.28 C-2.44,7.57 -1.39,8.63 -0.09,8.63c " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.372,0 0.203,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="strokeWidth"
+ android:duration="333"
+ android:startOffset="0"
+ android:valueFrom="1.5"
+ android:valueTo="2"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.307,0 0.386,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData"
+ android:duration="333"
+ android:startOffset="0"
+ android:valueFrom="M7.88 -0.62 C7.88,-0.62 7.88,9.38 7.88,9.38 C7.88,10.48 6.98,11.38 5.88,11.38 C5.88,11.38 -5.87,11.38 -5.87,11.38 C-6.98,11.38 -7.87,10.48 -7.87,9.38 C-7.87,9.38 -7.87,-0.62 -7.87,-0.62 C-7.87,-1.73 -6.98,-2.62 -5.87,-2.62 C-5.87,-2.62 5.88,-2.62 5.88,-2.62 C6.98,-2.62 7.88,-1.73 7.88,-0.62c " android:valueTo="M11.25 -0.64 C11.25,-0.64 11.25,13.64 11.25,13.64 C11.25,15.22 9.97,16.5 8.39,16.5 C8.39,16.5 -8.39,16.5 -8.39,16.5 C-9.97,16.5 -11.25,15.22 -11.25,13.64 C-11.25,13.64 -11.25,-0.64 -11.25,-0.64 C-11.25,-2.22 -9.97,-3.5 -8.39,-3.5 C-8.39,-3.5 8.39,-3.5 8.39,-3.5 C9.97,-3.5 11.25,-2.22 11.25,-0.64c " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.372,0 0.203,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="strokeWidth"
+ android:duration="333"
+ android:startOffset="0"
+ android:valueFrom="1.5"
+ android:valueTo="2.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData"
+ android:duration="333"
+ android:startOffset="0"
+ android:valueFrom="M21.25 14.88 C21.25,14.88 21.25,10.74 21.25,10.74 C21.25,8.59 19.5,7.29 17.44,7.21 C15.24,7.13 13.5,8.47 13.5,10.62 C13.5,10.62 13.5,15.75 13.5,15.75 " android:valueTo="M27.19 14.81 C27.19,14.81 27.19,8.3 27.19,8.3 C27.19,4.92 24.44,2.88 21.19,2.75 C17.74,2.62 15,4.74 15,8.11 C15,8.11 15,15 15,15 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.347,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX"
+ android:duration="517"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/drawable/unlocked_ls_to_aod.xml b/packages/SystemUI/res-keyguard/drawable/unlocked_ls_to_aod.xml
new file mode 100644
index 000000000000..1c6d0b5193eb
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/unlocked_ls_to_aod.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <aapt:attr name="android:drawable">
+ <vector android:height="65dp" android:width="46dp" android:viewportHeight="65" android:viewportWidth="46">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_2_G" android:translateX="23" android:translateY="32.125">
+ <path android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillColor="#FF000000"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-0.09 8.63 C1.2,8.63 2.25,7.57 2.25,6.28 C2.25,4.99 1.2,3.94 -0.09,3.94 C-1.39,3.94 -2.44,4.99 -2.44,6.28 C-2.44,7.57 -1.39,8.63 -0.09,8.63c " />
+ </group>
+ <group android:name="_R_G_L_1_G" android:translateX="23" android:translateY="32.125">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:strokeColor="#FF000000"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2"
+ android:strokeAlpha="1"
+ android:pathData=" M11.25 -0.64 C11.25,-0.64 11.25,13.64 11.25,13.64 C11.25,15.22 9.97,16.5 8.39,16.5 C8.39,16.5 -8.39,16.5 -8.39,16.5 C-9.97,16.5 -11.25,15.22 -11.25,13.64 C-11.25,13.64 -11.25,-0.64 -11.25,-0.64 C-11.25,-2.22 -9.97,-3.5 -8.39,-3.5 C-8.39,-3.5 8.39,-3.5 8.39,-3.5 C9.97,-3.5 11.25,-2.22 11.25,-0.64c " />
+ </group>
+ <group android:name="_R_G_L_0_G" android:translateX="14" android:translateY="13.5">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:strokeColor="#FF000000"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2.5"
+ android:strokeAlpha="1"
+ android:pathData=" M27.19 14.81 C27.19,14.81 27.19,8.3 27.19,8.3 C27.19,4.92 24.44,2.88 21.19,2.75 C17.74,2.62 15,4.74 15,8.11 C15,8.11 15,15 15,15 " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData"
+ android:duration="333"
+ android:startOffset="0"
+ android:valueFrom="M-0.09 8.63 C1.2,8.63 2.25,7.57 2.25,6.28 C2.25,4.99 1.2,3.94 -0.09,3.94 C-1.39,3.94 -2.44,4.99 -2.44,6.28 C-2.44,7.57 -1.39,8.63 -0.09,8.63c " android:valueTo="M0 6.13 C0.97,6.13 1.75,5.34 1.75,4.38 C1.75,3.41 0.97,2.63 0,2.63 C-0.97,2.63 -1.75,3.41 -1.75,4.38 C-1.75,5.34 -0.97,6.13 0,6.13c " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.347,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="strokeWidth"
+ android:duration="333"
+ android:startOffset="0"
+ android:valueFrom="2"
+ android:valueTo="1.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.516,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData"
+ android:duration="333"
+ android:startOffset="0"
+ android:valueFrom="M11.25 -0.64 C11.25,-0.64 11.25,13.64 11.25,13.64 C11.25,15.22 9.97,16.5 8.39,16.5 C8.39,16.5 -8.39,16.5 -8.39,16.5 C-9.97,16.5 -11.25,15.22 -11.25,13.64 C-11.25,13.64 -11.25,-0.64 -11.25,-0.64 C-11.25,-2.22 -9.97,-3.5 -8.39,-3.5 C-8.39,-3.5 8.39,-3.5 8.39,-3.5 C9.97,-3.5 11.25,-2.22 11.25,-0.64c " android:valueTo="M7.88 -0.62 C7.88,-0.62 7.88,9.38 7.88,9.38 C7.88,10.48 6.98,11.38 5.88,11.38 C5.88,11.38 -5.87,11.38 -5.87,11.38 C-6.98,11.38 -7.87,10.48 -7.87,9.38 C-7.87,9.38 -7.87,-0.62 -7.87,-0.62 C-7.87,-1.73 -6.98,-2.62 -5.87,-2.62 C-5.87,-2.62 5.88,-2.62 5.88,-2.62 C6.98,-2.62 7.88,-1.73 7.88,-0.62c " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.347,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="strokeWidth"
+ android:duration="333"
+ android:startOffset="0"
+ android:valueFrom="2.5"
+ android:valueTo="1.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.516,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData"
+ android:duration="333"
+ android:startOffset="0"
+ android:valueFrom="M27.19 14.81 C27.19,14.81 27.19,8.3 27.19,8.3 C27.19,4.92 24.44,2.88 21.19,2.75 C17.74,2.62 15,4.74 15,8.11 C15,8.11 15,15 15,15 " android:valueTo="M21.25 14.88 C21.25,14.88 21.25,10.74 21.25,10.74 C21.25,8.59 19.5,7.29 17.44,7.21 C15.24,7.13 13.5,8.47 13.5,10.62 C13.5,10.62 13.5,15.75 13.5,15.75 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.347,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX"
+ android:duration="517"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/drawable/unlocked_to_aod_lock.xml b/packages/SystemUI/res-keyguard/drawable/unlocked_to_aod_lock.xml
new file mode 100644
index 000000000000..b6d76e01ad95
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/unlocked_to_aod_lock.xml
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+<animated-vector xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android">
+ <aapt:attr name="android:drawable">
+ <vector android:height="65dp" android:width="46dp" android:viewportHeight="65" android:viewportWidth="46">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_2_G_T_1" android:translateX="22.75" android:translateY="22.25" android:scaleX="1.02" android:scaleY="1.02">
+ <group android:name="_R_G_L_2_G" android:translateX="-8.75" android:translateY="-8.75">
+ <path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#FF000000"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2.5"
+ android:strokeAlpha="1"
+ android:pathData=" M27.19 14.81 C27.19,14.81 27.19,8.3 27.19,8.3 C27.19,4.92 24.44,2.88 21.19,2.75 C17.74,2.62 15,4.74 15,8.11 C15,8.11 15,15 15,15 " />
+ </group>
+ </group>
+ <group android:name="_R_G_L_1_G" android:translateX="23" android:translateY="32.125">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:strokeColor="#FF000000"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2"
+ android:strokeAlpha="1"
+ android:pathData=" M11.25 -0.64 C11.25,-0.64 11.25,13.64 11.25,13.64 C11.25,15.22 9.97,16.5 8.39,16.5 C8.39,16.5 -8.39,16.5 -8.39,16.5 C-9.97,16.5 -11.25,15.22 -11.25,13.64 C-11.25,13.64 -11.25,-0.64 -11.25,-0.64 C-11.25,-2.22 -9.97,-3.5 -8.39,-3.5 C-8.39,-3.5 8.39,-3.5 8.39,-3.5 C9.97,-3.5 11.25,-2.22 11.25,-0.64c " />
+ </group>
+ <group android:name="_R_G_L_0_G" android:translateX="23" android:translateY="32.125">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="#FF000000"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-0.09 8.63 C1.2,8.63 2.25,7.57 2.25,6.28 C2.25,4.99 1.2,3.94 -0.09,3.94 C-1.39,3.94 -2.44,4.99 -2.44,6.28 C-2.44,7.57 -1.39,8.63 -0.09,8.63c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="strokeWidth"
+ android:duration="333" android:startOffset="0" android:valueFrom="2.5" android:valueTo="2" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0.833,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData"
+ android:duration="83" android:startOffset="0" android:valueFrom="M27.19 14.81 C27.19,14.81 27.19,8.3 27.19,8.3 C27.19,4.92 24.44,2.88 21.19,2.75 C17.74,2.62 15,4.74 15,8.11 C15,8.11 15,15 15,15 " android:valueTo="M27.13 10.19 C27.13,10.19 27.13,3.67 27.13,3.67 C27.13,0.3 24.38,-1.75 21.13,-1.87 C17.68,-2.01 14.94,0.11 14.94,3.49 C14.94,3.49 15,15 15,15 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.456,0 0.464,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData"
+ android:duration="133" android:startOffset="83" android:valueFrom="M27.13 10.19 C27.13,10.19 27.13,3.67 27.13,3.67 C27.13,0.3 24.38,-1.75 21.13,-1.87 C17.68,-2.01 14.94,0.11 14.94,3.49 C14.94,3.49 15,15 15,15 " android:valueTo="M2.5 10.38 C2.5,10.38 2.5,3.99 2.5,3.99 C2.5,0.61 5.3,-2.12 8.75,-2.12 C12.2,-2.12 15,0.61 15,3.99 C15,3.99 15,15 15,15 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.606,0 0.035,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="pathData"
+ android:duration="117" android:startOffset="217" android:valueFrom="M2.5 10.38 C2.5,10.38 2.5,3.99 2.5,3.99 C2.5,0.61 5.3,-2.12 8.75,-2.12 C12.2,-2.12 15,0.61 15,3.99 C15,3.99 15,15 15,15 " android:valueTo="M2.5 15 C2.5,15 2.5,8.61 2.5,8.61 C2.5,5.24 5.3,2.5 8.75,2.5 C12.2,2.5 15,5.24 15,8.61 C15,8.61 15,15 15,15 " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.511,0 0.409,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX"
+ android:duration="333" android:startOffset="0" android:valueFrom="22.75" android:valueTo="23" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateY" android:duration="333" android:startOffset="0" android:valueFrom="22.25" android:valueTo="25.5" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="scaleX"
+ android:duration="333" android:startOffset="0" android:valueFrom="1.02" android:valueTo="0.72" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY"
+ android:duration="333" android:startOffset="0" android:valueFrom="1.02" android:valueTo="0.72" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="strokeWidth"
+ android:duration="333" android:startOffset="0" android:valueFrom="2" android:valueTo="1.5" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.38,0 0.274,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData"
+ android:duration="333" android:startOffset="0" android:valueFrom="M11.25 -0.64 C11.25,-0.64 11.25,13.64 11.25,13.64 C11.25,15.22 9.97,16.5 8.39,16.5 C8.39,16.5 -8.39,16.5 -8.39,16.5 C-9.97,16.5 -11.25,15.22 -11.25,13.64 C-11.25,13.64 -11.25,-0.64 -11.25,-0.64 C-11.25,-2.22 -9.97,-3.5 -8.39,-3.5 C-8.39,-3.5 8.39,-3.5 8.39,-3.5 C9.97,-3.5 11.25,-2.22 11.25,-0.64c " android:valueTo="M7.88 -0.62 C7.88,-0.62 7.88,9.38 7.88,9.38 C7.88,10.48 6.98,11.38 5.88,11.38 C5.88,11.38 -5.87,11.38 -5.87,11.38 C-6.98,11.38 -7.87,10.48 -7.87,9.38 C-7.87,9.38 -7.87,-0.62 -7.87,-0.62 C-7.87,-1.73 -6.98,-2.62 -5.87,-2.62 C-5.87,-2.62 5.88,-2.62 5.88,-2.62 C6.98,-2.62 7.88,-1.73 7.88,-0.62c " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.431,0 0.133,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData"
+ android:duration="333" android:startOffset="0" android:valueFrom="M-0.09 8.63 C1.2,8.63 2.25,7.57 2.25,6.28 C2.25,4.99 1.2,3.94 -0.09,3.94 C-1.39,3.94 -2.44,4.99 -2.44,6.28 C-2.44,7.57 -1.39,8.63 -0.09,8.63c " android:valueTo="M0 6.13 C0.97,6.13 1.75,5.34 1.75,4.38 C1.75,3.41 0.97,2.63 0,2.63 C-0.97,2.63 -1.75,3.41 -1.75,4.38 C-1.75,5.34 -0.97,6.13 0,6.13c " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.431,0 0.133,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX"
+ android:duration="850" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml b/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml
deleted file mode 100644
index 50267fda0b25..000000000000
--- a/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 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
- -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:shape="rectangle">
- <stroke
- android:color="?androidprv:attr/colorAccentPrimaryVariant"
- android:width="1dp"/>
- <corners android:radius="20dp"/>
- <padding
- android:left="8dp"
- android:right="8dp"
- android:top="4dp"
- android:bottom="4dp" />
- <solid android:color="@android:color/transparent" />
-</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml b/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml
index 665b4564ebf1..a47299d6f854 100644
--- a/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml
+++ b/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml
@@ -29,7 +29,7 @@
<shape android:shape="rectangle">
<corners android:radius="?android:attr/buttonCornerRadius"/>
<solid android:color="@android:color/transparent"/>
- <stroke android:color="?androidprv:attr/colorAccentPrimary"
+ <stroke android:color="?androidprv:attr/colorAccentPrimaryVariant"
android:width="1dp"
/>
<padding android:left="@dimen/dialog_button_horizontal_padding"
diff --git a/packages/SystemUI/res/drawable/screenrecord_button_background_outline.xml b/packages/SystemUI/res/drawable/screenrecord_button_background_outline.xml
deleted file mode 100644
index 59a31e8f6136..000000000000
--- a/packages/SystemUI/res/drawable/screenrecord_button_background_outline.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 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
- -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:shape="rectangle">
- <stroke
- android:color="?androidprv:attr/colorAccentPrimary"
- android:width="1dp"/>
- <corners android:radius="24dp"/>
- <padding
- android:left="16dp"
- android:right="16dp"
- android:top="8dp"
- android:bottom="8dp" />
- <solid android:color="@android:color/transparent" />
-</shape>
diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml
index 3c9e44e2dba9..89690e8ff0ec 100644
--- a/packages/SystemUI/res/layout/auth_biometric_contents.xml
+++ b/packages/SystemUI/res/layout/auth_biometric_contents.xml
@@ -73,6 +73,9 @@
android:accessibilityLiveRegion="polite"
android:singleLine="true"
android:ellipsize="marquee"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:scrollHorizontally="true"
+ android:fadingEdge="horizontal"
android:textColor="@color/biometric_dialog_gray"/>
<LinearLayout
diff --git a/packages/SystemUI/res/layout/auth_credential_password_view.xml b/packages/SystemUI/res/layout/auth_credential_password_view.xml
index 46cbc253175e..1e0ce0026d8e 100644
--- a/packages/SystemUI/res/layout/auth_credential_password_view.xml
+++ b/packages/SystemUI/res/layout/auth_credential_password_view.xml
@@ -18,71 +18,64 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:elevation="@dimen/biometric_dialog_elevation"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:gravity="center_horizontal"
+ android:elevation="@dimen/biometric_dialog_elevation">
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout
- android:id="@+id/auth_credential_header"
- style="@style/AuthCredentialHeaderStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true">
-
- <ImageView
- android:id="@+id/icon"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:contentDescription="@null" />
-
- <TextView
- android:id="@+id/title"
- style="@style/TextAppearance.AuthCredential.Title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
- <TextView
- android:id="@+id/subtitle"
- style="@style/TextAppearance.AuthCredential.Subtitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
- <TextView
- android:id="@+id/description"
- style="@style/TextAppearance.AuthCredential.Description"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.AuthCredential.Title"/>
- </LinearLayout>
+ <TextView
+ android:id="@+id/subtitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.AuthCredential.Subtitle"/>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="vertical"
- android:layout_alignParentBottom="true">
+ <TextView
+ android:id="@+id/description"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.AuthCredential.Description"/>
- <ImeAwareEditText
- android:id="@+id/lockPassword"
- style="@style/TextAppearance.AuthCredential.PasswordEntry"
- android:layout_width="208dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
- android:inputType="textPassword"
- android:minHeight="48dp" />
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
- <TextView
- android:id="@+id/error"
- style="@style/TextAppearance.AuthCredential.Error"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ <ImeAwareEditText
+ android:id="@+id/lockPassword"
+ android:layout_width="208dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:minHeight="48dp"
+ android:gravity="center"
+ android:inputType="textPassword"
+ android:maxLength="500"
+ android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
+ style="@style/TextAppearance.AuthCredential.PasswordEntry"/>
- </LinearLayout>
+ <TextView
+ android:id="@+id/error"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.AuthCredential.Error"/>
- </RelativeLayout>
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="5"/>
</com.android.systemui.biometrics.AuthCredentialPasswordView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
index 470298ea0b13..4939ea2c99ee 100644
--- a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
+++ b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
@@ -22,81 +22,76 @@
android:gravity="center_horizontal"
android:elevation="@dimen/biometric_dialog_elevation">
- <RelativeLayout
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <TextView
+ android:id="@+id/title"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.AuthCredential.Title"/>
- <LinearLayout
- android:id="@+id/auth_credential_header"
- style="@style/AuthCredentialHeaderStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <ImageView
- android:id="@+id/icon"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:contentDescription="@null" />
-
- <TextView
- android:id="@+id/title"
- style="@style/TextAppearance.AuthCredential.Title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <TextView
- android:id="@+id/subtitle"
- style="@style/TextAppearance.AuthCredential.Subtitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <TextView
- android:id="@+id/description"
- style="@style/TextAppearance.AuthCredential.Description"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/auth_credential_header"
- android:gravity="center"
- android:orientation="vertical"
- android:paddingBottom="16dp"
- android:paddingTop="60dp">
+ <TextView
+ android:id="@+id/subtitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.AuthCredential.Subtitle"/>
- <FrameLayout
- style="@style/LockPatternContainerStyle"
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- android:layout_weight="1">
+ <TextView
+ android:id="@+id/description"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.AuthCredential.Description"/>
- <com.android.internal.widget.LockPatternView
- android:id="@+id/lockPattern"
- style="@style/LockPatternStyle"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center" />
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
- </FrameLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingLeft="0dp"
+ android:paddingRight="0dp"
+ android:paddingTop="0dp"
+ android:paddingBottom="16dp"
+ android:clipToPadding="false">
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ style="@style/LockPatternContainerStyle">
+
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPattern"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ style="@style/LockPatternStyleBiometricPrompt"/>
- </LinearLayout>
+ </FrameLayout>
- <LinearLayout
+ <TextView
+ android:id="@+id/error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentBottom="true">
-
- <TextView
- android:id="@+id/error"
- style="@style/TextAppearance.AuthCredential.Error"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ style="@style/TextAppearance.AuthCredential.Error"/>
- </LinearLayout>
+ </LinearLayout>
- </RelativeLayout>
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
</com.android.systemui.biometrics.AuthCredentialPatternView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index c575855d9af8..275e0a52ab45 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -37,7 +37,7 @@
android:ellipsize="end"
android:gravity="center_vertical|center_horizontal"
android:layout_width="wrap_content"
- android:layout_height="32dp"
+ android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.InternetDialog"
android:textSize="24sp"/>
@@ -45,7 +45,7 @@
android:id="@+id/internet_dialog_subtitle"
android:gravity="center_vertical|center_horizontal"
android:layout_width="wrap_content"
- android:layout_height="20dp"
+ android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:ellipsize="end"
android:maxLines="1"
@@ -150,6 +150,7 @@
android:gravity="start|center_vertical">
<TextView
android:id="@+id/mobile_title"
+ android:maxLines="1"
style="@style/InternetDialog.NetworkTitle"/>
<TextView
android:id="@+id/mobile_summary"
@@ -380,54 +381,44 @@
android:id="@+id/button_layout"
android:orientation="horizontal"
android:layout_width="match_parent"
- android:layout_height="48dp"
- android:layout_marginStart="24dp"
- android:layout_marginEnd="24dp"
+ android:layout_height="wrap_content"
android:layout_marginTop="8dp"
- android:layout_marginBottom="34dp"
+ android:layout_marginStart="@dimen/dialog_side_padding"
+ android:layout_marginEnd="@dimen/dialog_side_padding"
+ android:layout_marginBottom="@dimen/dialog_bottom_padding"
android:clickable="false"
android:focusable="false">
<FrameLayout
android:id="@+id/apm_layout"
android:layout_width="wrap_content"
- android:layout_height="48dp"
+ android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:layout_gravity="start|center_vertical"
android:orientation="vertical">
<Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:text="@string/turn_off_airplane_mode"
android:ellipsize="end"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="36dp"
- android:layout_gravity="start|center_vertical"
- android:textAppearance="@style/TextAppearance.InternetDialog"
- android:textSize="14sp"
- android:background="@drawable/internet_dialog_footer_background"
+ style="@style/Widget.Dialog.Button.BorderButton"
android:clickable="false"/>
</FrameLayout>
<FrameLayout
android:id="@+id/done_layout"
android:layout_width="wrap_content"
- android:layout_height="48dp"
+ android:layout_height="wrap_content"
android:layout_marginStart="16dp"
- android:clickable="true"
- android:focusable="true"
android:layout_gravity="end|center_vertical"
- android:orientation="vertical">
+ android:clickable="true"
+ android:focusable="true">
<Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:text="@string/inline_done_button"
- android:ellipsize="end"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_width="67dp"
- android:layout_height="36dp"
- android:layout_gravity="end|center_vertical"
- android:textAppearance="@style/TextAppearance.InternetDialog"
- android:textSize="14sp"
- android:background="@drawable/internet_dialog_footer_background"
+ style="@style/Widget.Dialog.Button"
android:clickable="false"/>
</FrameLayout>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index 07fd1b0c001c..3a186d2cc8d2 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -89,17 +89,16 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
- android:layout_marginStart="24dp"
- android:layout_marginBottom="24dp"
- android:layout_marginEnd="24dp"
+ android:layout_marginStart="@dimen/dialog_side_padding"
+ android:layout_marginEnd="@dimen/dialog_side_padding"
+ android:layout_marginBottom="@dimen/dialog_bottom_padding"
android:orientation="horizontal">
<Button
android:id="@+id/stop"
- style="@style/MediaOutputRoundedOutlinedButton"
+ style="@style/Widget.Dialog.Button.BorderButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:minWidth="0dp"
android:text="@string/keyboard_key_media_stop"
android:visibility="gone"/>
@@ -110,10 +109,9 @@
<Button
android:id="@+id/done"
- style="@style/MediaOutputRoundedOutlinedButton"
+ style="@style/Widget.Dialog.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:minWidth="0dp"
android:text="@string/inline_done_button"/>
</LinearLayout>
</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml
index 6c5ad5060495..6012b58d0293 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog.xml
@@ -27,10 +27,10 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingStart="24dp"
- android:paddingEnd="24dp"
- android:paddingTop="26dp"
- android:paddingBottom="30dp"
+ android:paddingStart="@dimen/dialog_side_padding"
+ android:paddingEnd="@dimen/dialog_side_padding"
+ android:paddingTop="@dimen/dialog_top_padding"
+ android:paddingBottom="@dimen/dialog_bottom_padding"
android:orientation="vertical">
<!-- Header -->
@@ -108,10 +108,7 @@
android:layout_weight="0"
android:layout_gravity="start"
android:text="@string/cancel"
- android:textColor="?android:textColorPrimary"
- android:background="@drawable/screenrecord_button_background_outline"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textSize="14sp"/>
+ style="@style/Widget.Dialog.Button.BorderButton" />
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
@@ -123,10 +120,7 @@
android:layout_weight="0"
android:layout_gravity="end"
android:text="@string/screenrecord_start"
- android:textColor="@android:color/system_neutral1_900"
- android:background="@drawable/screenrecord_button_background_solid"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textSize="14sp"/>
+ style="@style/Widget.Dialog.Button" />
</LinearLayout>
</LinearLayout>
</ScrollView>
diff --git a/packages/SystemUI/res/layout/status_bar_no_notifications.xml b/packages/SystemUI/res/layout/status_bar_no_notifications.xml
index 332dc6ee8656..a2abdb211602 100644
--- a/packages/SystemUI/res/layout/status_bar_no_notifications.xml
+++ b/packages/SystemUI/res/layout/status_bar_no_notifications.xml
@@ -26,8 +26,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="64dp"
- android:paddingTop="12dp"
android:textAppearance="?android:attr/textAppearanceButton"
- android:gravity="top|center_horizontal"
+ android:gravity="center"
android:text="@string/empty_shade_text"/>
</com.android.systemui.statusbar.EmptyShadeView>
diff --git a/packages/SystemUI/res/values-h800dp/dimens.xml b/packages/SystemUI/res/values-h800dp/dimens.xml
index f057603e2cd0..1d6f279afc66 100644
--- a/packages/SystemUI/res/values-h800dp/dimens.xml
+++ b/packages/SystemUI/res/values-h800dp/dimens.xml
@@ -22,5 +22,5 @@
<dimen name="large_clock_text_size">200dp</dimen>
<!-- With the large clock, move up slightly from the center -->
- <dimen name="keyguard_large_clock_top_margin">-104dp</dimen>
+ <dimen name="keyguard_large_clock_top_margin">-112dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index b98694e2fae7..fcb369876cf2 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -77,7 +77,7 @@
<color name="biometric_dialog_error">#fff28b82</color> <!-- red 300 -->
<!-- UDFPS colors -->
- <color name="udfps_enroll_icon">#ffffff</color> <!-- 100% white -->
+ <color name="udfps_enroll_icon">#7DA7F1</color>
<color name="GM2_green_500">#FF41Af6A</color>
<color name="GM2_blue_500">#5195EA</color>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 8a3bacae9243..e455aaa225be 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -134,10 +134,10 @@
<color name="biometric_dialog_error">#ffd93025</color> <!-- red 600 -->
<!-- UDFPS colors -->
- <color name="udfps_enroll_icon">#000000</color> <!-- 100% black -->
- <color name="udfps_moving_target_fill">#cc4285f4</color> <!-- 80% blue -->
- <color name="udfps_enroll_progress">#ff669DF6</color> <!-- blue 400 -->
- <color name="udfps_enroll_progress_help">#ffEE675C</color> <!-- red 400 -->
+ <color name="udfps_enroll_icon">#7DA7F1</color>
+ <color name="udfps_moving_target_fill">#475670</color>
+ <color name="udfps_enroll_progress">#7DA7F1</color>
+ <color name="udfps_enroll_progress_help">#ffEE675C</color>
<!-- Global screenshot actions -->
<color name="global_screenshot_button_ripple">#1f000000</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 475f70fa9fdc..e00b9410a8a7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -595,17 +595,6 @@
280
</integer>
- <!-- Haptic feedback intensity for ticks used for the udfps dwell time -->
- <item name="config_udfpsTickIntensity" translatable="false" format="float"
- type="dimen">.5</item>
-
- <!-- Haptic feedback delay between ticks used for udfps dwell time -->
- <integer name="config_udfpsTickDelay" translatable="false">25</integer>
-
- <!-- Haptic feedback tick type - if true, uses VibrationEffect.Composition.PRIMITIVE_LOW_TICK
- else uses VibrationEffect.Composition.PRIMITIVE_TICK -->
- <bool name="config_udfpsUseLowTick">true</bool>
-
<!-- package name of a built-in camera app to use to restrict implicit intent resolution
when the double-press power gesture is used. Ignored if empty. -->
<string translatable="false" name="config_cameraGesturePackage"></string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1938e48e859a..a67d5c254ebf 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -601,7 +601,7 @@
<!-- When large clock is showing, offset the smartspace by this amount -->
<dimen name="keyguard_smartspace_top_offset">12dp</dimen>
<!-- With the large clock, move up slightly from the center -->
- <dimen name="keyguard_large_clock_top_margin">-52dp</dimen>
+ <dimen name="keyguard_large_clock_top_margin">-60dp</dimen>
<!-- Default line spacing multiplier between hours and minutes of the keyguard clock -->
<item name="keyguard_clock_line_spacing_scale" type="dimen" format="float">.7</item>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 0cfd8d6d0716..051a30ccb524 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -200,9 +200,9 @@
<style name="TextAppearance.DeviceManagementDialog.Title" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"/>
- <style name="TextAppearance.AuthCredential"
- parent="@android:style/TextAppearance.DeviceDefault">
+ <style name="TextAppearance.AuthCredential">
<item name="android:accessibilityLiveRegion">polite</item>
+ <item name="android:gravity">center_horizontal</item>
<item name="android:textAlignment">gravity</item>
<item name="android:layout_gravity">top</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
@@ -210,57 +210,44 @@
<style name="TextAppearance.AuthCredential.Title">
<item name="android:fontFamily">google-sans</item>
- <item name="android:layout_marginTop">20dp</item>
- <item name="android:textSize">36sp</item>
+ <item name="android:paddingTop">12dp</item>
+ <item name="android:paddingHorizontal">24dp</item>
+ <item name="android:textSize">24sp</item>
</style>
<style name="TextAppearance.AuthCredential.Subtitle">
<item name="android:fontFamily">google-sans</item>
- <item name="android:layout_marginTop">20dp</item>
- <item name="android:textSize">18sp</item>
+ <item name="android:paddingTop">8dp</item>
+ <item name="android:paddingHorizontal">24dp</item>
+ <item name="android:textSize">16sp</item>
</style>
<style name="TextAppearance.AuthCredential.Description">
<item name="android:fontFamily">google-sans</item>
- <item name="android:layout_marginTop">20dp</item>
- <item name="android:textSize">16sp</item>
+ <item name="android:paddingTop">8dp</item>
+ <item name="android:paddingHorizontal">24dp</item>
+ <item name="android:textSize">14sp</item>
</style>
<style name="TextAppearance.AuthCredential.Error">
<item name="android:paddingTop">6dp</item>
- <item name="android:paddingBottom">18dp</item>
<item name="android:paddingHorizontal">24dp</item>
<item name="android:textSize">14sp</item>
<item name="android:textColor">?android:attr/colorError</item>
- <item name="android:gravity">center</item>
</style>
- <style name="TextAppearance.AuthCredential.PasswordEntry">
+ <style name="TextAppearance.AuthCredential.PasswordEntry" parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:gravity">center</item>
<item name="android:singleLine">true</item>
<item name="android:textColor">?android:attr/colorForeground</item>
<item name="android:textSize">24sp</item>
</style>
- <style name="AuthCredentialHeaderStyle">
- <item name="android:paddingStart">48dp</item>
- <item name="android:paddingEnd">24dp</item>
- <item name="android:paddingTop">28dp</item>
- <item name="android:paddingBottom">20dp</item>
- <item name="android:orientation">vertical</item>
- <item name="android:layout_gravity">top</item>
- </style>
-
<style name="DeviceManagementDialogTitle">
<item name="android:gravity">center</item>
<item name="android:textAppearance">@style/TextAppearance.DeviceManagementDialog.Title</item>
</style>
- <style name="AuthCredentialPasswordTheme" parent="@style/Theme.MaterialComponents.DayNight">
- <item name="colorPrimary">?android:attr/colorPrimary</item>
- <item name="colorPrimaryDark">?android:attr/colorPrimary</item>
- </style>
-
<style name="TextAppearance.DeviceManagementDialog.Content" parent="@*android:style/TextAppearance.DeviceDefault.Subhead"/>
<style name="BaseBrightnessDialogContainer" parent="@style/Theme.SystemUI">
@@ -320,8 +307,9 @@
<item name="android:maxWidth">420dp</item>
<item name="android:minHeight">0dp</item>
<item name="android:minWidth">0dp</item>
- <item name="android:paddingHorizontal">60dp</item>
- <item name="android:paddingBottom">40dp</item>
+ <item name="android:paddingBottom">0dp</item>
+ <item name="android:paddingHorizontal">44dp</item>
+ <item name="android:paddingTop">0dp</item>
</style>
<style name="LockPatternStyle">
@@ -462,10 +450,6 @@
<item name="android:background">@drawable/btn_borderless_rect</item>
</style>
- <style name="MediaOutputRoundedOutlinedButton" parent="@android:style/Widget.Material.Button">
- <item name="android:background">@drawable/media_output_dialog_button_background</item>
- </style>
-
<style name="TunerSettings" parent="@android:style/Theme.DeviceDefault.Settings">
<item name="android:windowActionBar">false</item>
<item name="preferenceTheme">@style/TunerPreferenceTheme</item>
@@ -893,13 +877,18 @@
<item name="android:textAlignment">center</item>
</style>
- <style name="Widget.Dialog.Button" parent = "Theme.SystemUI.Dialog">
+
+ <style name="Widget" />
+ <style name="Widget.Dialog" />
+ <style name="Widget.Dialog.Button">
+ <item name="android:buttonCornerRadius">28dp</item>
<item name="android:background">@drawable/qs_dialog_btn_filled</item>
<item name="android:textColor">?androidprv:attr/textColorOnAccent</item>
<item name="android:textSize">14sp</item>
<item name="android:lineHeight">20sp</item>
<item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
<item name="android:stateListAnimator">@null</item>
+ <item name="android:minWidth">0dp</item>
</style>
<style name="Widget.Dialog.Button.BorderButton">
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
index 7d0fb5d38849..567e7aa3d78f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
@@ -53,8 +53,8 @@ public class PipSurfaceTransactionHelper {
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setPosition(leash, positionX, positionY)
.setCornerRadius(leash, cornerRadius);
- return new PictureInPictureSurfaceTransaction(
- positionX, positionY, mTmpFloat9, 0 /* rotation */, cornerRadius, sourceBounds);
+ return newPipSurfaceTransaction(positionX, positionY,
+ mTmpFloat9, 0 /* rotation */, cornerRadius, sourceBounds);
}
public PictureInPictureSurfaceTransaction scale(
@@ -70,8 +70,8 @@ public class PipSurfaceTransactionHelper {
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
.setPosition(leash, positionX, positionY)
.setCornerRadius(leash, cornerRadius);
- return new PictureInPictureSurfaceTransaction(
- positionX, positionY, mTmpFloat9, degree, cornerRadius, sourceBounds);
+ return newPipSurfaceTransaction(positionX, positionY,
+ mTmpFloat9, degree, cornerRadius, sourceBounds);
}
public PictureInPictureSurfaceTransaction scaleAndCrop(
@@ -93,8 +93,8 @@ public class PipSurfaceTransactionHelper {
.setWindowCrop(leash, mTmpDestinationRect)
.setPosition(leash, left, top)
.setCornerRadius(leash, cornerRadius);
- return new PictureInPictureSurfaceTransaction(
- left, top, mTmpFloat9, 0 /* rotation */, cornerRadius, mTmpDestinationRect);
+ return newPipSurfaceTransaction(left, top,
+ mTmpFloat9, 0 /* rotation */, cornerRadius, mTmpDestinationRect);
}
public PictureInPictureSurfaceTransaction scaleAndRotate(
@@ -125,8 +125,7 @@ public class PipSurfaceTransactionHelper {
.setWindowCrop(leash, mTmpDestinationRect)
.setPosition(leash, adjustedPositionX, adjustedPositionY)
.setCornerRadius(leash, cornerRadius);
- return new PictureInPictureSurfaceTransaction(
- adjustedPositionX, adjustedPositionY,
+ return newPipSurfaceTransaction(adjustedPositionX, adjustedPositionY,
mTmpFloat9, degree, cornerRadius, mTmpDestinationRect);
}
@@ -137,6 +136,17 @@ public class PipSurfaceTransactionHelper {
return mCornerRadius * scale;
}
+ private static PictureInPictureSurfaceTransaction newPipSurfaceTransaction(
+ float posX, float posY, float[] float9, float rotation, float cornerRadius,
+ Rect windowCrop) {
+ return new PictureInPictureSurfaceTransaction.Builder()
+ .setPosition(posX, posY)
+ .setTransform(float9, rotation)
+ .setCornerRadius(cornerRadius)
+ .setWindowCrop(windowCrop)
+ .build();
+ }
+
/** @return {@link SurfaceControl.Transaction} instance with vsync-id */
public static SurfaceControl.Transaction newSurfaceControlTransaction() {
final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index c628d4401bb1..324fae161afc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -89,7 +89,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final KeyguardBypassController mBypassController;
- private int mLargeClockTopMargin = 0;
private int mKeyguardClockTopMargin = 0;
/**
@@ -276,16 +275,13 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
}
private void updateClockLayout() {
- if (mSmartspaceController.isEnabled()) {
- RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT,
- MATCH_PARENT);
- mLargeClockTopMargin = getContext().getResources().getDimensionPixelSize(
- R.dimen.keyguard_large_clock_top_margin);
- lp.topMargin = mLargeClockTopMargin;
- mLargeClockFrame.setLayoutParams(lp);
- } else {
- mLargeClockTopMargin = 0;
- }
+ int largeClockTopMargin = getContext().getResources().getDimensionPixelSize(
+ R.dimen.keyguard_large_clock_top_margin);
+
+ RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT,
+ MATCH_PARENT);
+ lp.topMargin = largeClockTopMargin;
+ mLargeClockFrame.setLayoutParams(lp);
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index e267c5c7919c..cc452c6f3b79 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -35,12 +35,10 @@ import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.media.AudioAttributes;
import android.os.Process;
-import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.MathUtils;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
@@ -68,8 +66,6 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.concurrency.DelayableExecutor;
-import com.airbnb.lottie.LottieAnimationView;
-
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Objects;
@@ -104,10 +100,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
@NonNull private final AccessibilityManager mAccessibilityManager;
@NonNull private final ConfigurationController mConfigurationController;
@NonNull private final DelayableExecutor mExecutor;
- @NonNull private final LayoutInflater mLayoutInflater;
private boolean mUdfpsEnrolled;
- @Nullable private LottieAnimationView mAodFp;
@NonNull private final AnimatedStateListDrawable mIcon;
@NonNull private CharSequence mUnlockedLabel;
@@ -119,7 +113,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
private VelocityTracker mVelocityTracker;
// The ID of the pointer for which ACTION_DOWN has occurred. -1 means no pointer is active.
private int mActivePointerId = -1;
- private VibrationEffect mTick;
private boolean mIsDozing;
private boolean mIsBouncerShowing;
@@ -143,7 +136,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
// for udfps when strong auth is required or unlocked on AOD
private boolean mShowAodLockIcon;
- private boolean mShowAODFpIcon;
+ private boolean mShowAodUnlockedIcon;
private final int mMaxBurnInOffsetX;
private final int mMaxBurnInOffsetY;
private float mInterpolatedDarkAmount;
@@ -166,8 +159,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
@NonNull @Main DelayableExecutor executor,
@Nullable Vibrator vibrator,
@Nullable AuthRippleController authRippleController,
- @NonNull @Main Resources resources,
- @NonNull LayoutInflater inflater
+ @NonNull @Main Resources resources
) {
super(view);
mStatusBarStateController = statusBarStateController;
@@ -181,7 +173,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mExecutor = executor;
mVibrator = vibrator;
mAuthRippleController = authRippleController;
- mLayoutInflater = inflater;
mMaxBurnInOffsetX = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
mMaxBurnInOffsetY = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
@@ -263,11 +254,12 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
}
boolean wasShowingUnlock = mShowUnlockIcon;
- boolean wasShowingFpIcon = mUdfpsEnrolled && !mShowUnlockIcon && !mShowLockIcon;
+ boolean wasShowingFpIcon = mUdfpsEnrolled && !mShowUnlockIcon && !mShowLockIcon
+ && !mShowAodUnlockedIcon && !mShowAodLockIcon;
mShowLockIcon = !mCanDismissLockScreen && !mUserUnlockedWithBiometric && isLockScreen()
&& (!mUdfpsEnrolled || !mRunningFPS);
mShowUnlockIcon = (mCanDismissLockScreen || mUserUnlockedWithBiometric) && isLockScreen();
- mShowAODFpIcon = mIsDozing && mUdfpsEnrolled && !mRunningFPS && mCanDismissLockScreen;
+ mShowAodUnlockedIcon = mIsDozing && mUdfpsEnrolled && !mRunningFPS && mCanDismissLockScreen;
mShowAodLockIcon = mIsDozing && mUdfpsEnrolled && !mRunningFPS && !mCanDismissLockScreen;
final CharSequence prevContentDescription = mView.getContentDescription();
@@ -284,20 +276,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mView.updateIcon(ICON_UNLOCK, false);
mView.setContentDescription(mUnlockedLabel);
mView.setVisibility(View.VISIBLE);
- } else if (mShowAODFpIcon) {
- // AOD fp icon is special cased as a lottie view (it updates for each burn-in offset),
- // this state shows a transparent view
- mView.setContentDescription(null);
- mAodFp.setVisibility(View.VISIBLE);
- mAodFp.setContentDescription(mCanDismissLockScreen ? mUnlockedLabel : mLockedLabel);
-
- mView.updateIcon(ICON_FINGERPRINT, true); // this shows no icon
+ } else if (mShowAodUnlockedIcon) {
+ mView.updateIcon(ICON_UNLOCK, true);
+ mView.setContentDescription(mUnlockedLabel);
mView.setVisibility(View.VISIBLE);
} else if (mShowAodLockIcon) {
- if (wasShowingUnlock) {
- // transition to the unlock icon first
- mView.updateIcon(ICON_LOCK, false);
- }
mView.updateIcon(ICON_LOCK, true);
mView.setContentDescription(mLockedLabel);
mView.setVisibility(View.VISIBLE);
@@ -307,11 +290,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mView.setContentDescription(null);
}
- if (!mShowAODFpIcon && mAodFp != null) {
- mAodFp.setVisibility(View.INVISIBLE);
- mAodFp.setContentDescription(null);
- }
-
if (!Objects.equals(prevContentDescription, mView.getContentDescription())
&& mView.getContentDescription() != null) {
mView.announceForAccessibility(mView.getContentDescription());
@@ -399,7 +377,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
pw.println();
pw.println(" mShowUnlockIcon: " + mShowUnlockIcon);
pw.println(" mShowLockIcon: " + mShowLockIcon);
- pw.println(" mShowAODFpIcon: " + mShowAODFpIcon);
+ pw.println(" mShowAodUnlockedIcon: " + mShowAodUnlockedIcon);
pw.println(" mIsDozing: " + mIsDozing);
pw.println(" mIsBouncerShowing: " + mIsBouncerShowing);
pw.println(" mUserUnlockedWithBiometric: " + mUserUnlockedWithBiometric);
@@ -428,13 +406,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
- mMaxBurnInOffsetY, mInterpolatedDarkAmount);
float progress = MathUtils.lerp(0f, getBurnInProgressOffset(), mInterpolatedDarkAmount);
- if (mAodFp != null) {
- mAodFp.setTranslationX(offsetX);
- mAodFp.setTranslationY(offsetY);
- mAodFp.setProgress(progress);
- mAodFp.setAlpha(255 * mInterpolatedDarkAmount);
- }
-
mView.setTranslationX(offsetX);
mView.setTranslationY(offsetY);
}
@@ -447,10 +418,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mView.setUseBackground(mUdfpsSupported);
mUdfpsEnrolled = mKeyguardUpdateMonitor.isUdfpsEnrolled();
- if (!wasUdfpsEnrolled && mUdfpsEnrolled && mAodFp == null) {
- mLayoutInflater.inflate(R.layout.udfps_aod_lock_icon, mView);
- mAodFp = mView.findViewById(R.id.lock_udfps_aod_fp);
- }
if (wasUdfpsSupported != mUdfpsSupported || wasUdfpsEnrolled != mUdfpsEnrolled) {
updateVisibility();
}
@@ -597,15 +564,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_HOVER_ENTER:
if (mVibrator != null && !mDownDetected) {
- if (mTick == null) {
- mTick = UdfpsController.lowTick(getContext(), true,
- LONG_PRESS_TIMEOUT);
- }
mVibrator.vibrate(
Process.myUid(),
getContext().getOpPackageName(),
- mTick,
- "lock-icon-tick",
+ UdfpsController.EFFECT_CLICK,
+ "lock-icon-down",
VIBRATION_SONIFICATION_ATTRIBUTES);
}
@@ -718,8 +681,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
private boolean inLockIconArea(MotionEvent event) {
return mSensorTouchLocation.contains((int) event.getX(), (int) event.getY())
- && (mView.getVisibility() == View.VISIBLE
- || (mAodFp != null && mAodFp.getVisibility() == View.VISIBLE));
+ && mView.getVisibility() == View.VISIBLE;
}
private boolean isActionable() {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index bb0e79fe23a8..db88569382a7 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -121,7 +121,7 @@ public class SystemUIFactory {
.setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper())
.setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper())
.setRecentTasks(mWMComponent.getRecentTasks())
- .setSizeCompatUI(Optional.of(mWMComponent.getSizeCompatUI()))
+ .setCompatUI(Optional.of(mWMComponent.getCompatUI()))
.setDragAndDrop(Optional.of(mWMComponent.getDragAndDrop()));
} else {
// TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
@@ -141,7 +141,7 @@ public class SystemUIFactory {
.setStartingSurface(Optional.ofNullable(null))
.setTaskSurfaceHelper(Optional.ofNullable(null))
.setRecentTasks(Optional.ofNullable(null))
- .setSizeCompatUI(Optional.ofNullable(null))
+ .setCompatUI(Optional.ofNullable(null))
.setDragAndDrop(Optional.ofNullable(null));
}
mSysUIComponent = builder.build();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index f11dc9313852..e35b55841f2f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -636,6 +636,7 @@ public abstract class AuthBiometricView extends LinearLayout {
mIndicatorView.setText(message);
mIndicatorView.setTextColor(mTextColorError);
mIndicatorView.setVisibility(View.VISIBLE);
+ mIndicatorView.setSelected(true);
mHandler.postDelayed(resetMessageRunnable, mInjector.getDelayAfterError());
Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
index fb4616a832dc..07aec6994bd0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
@@ -23,6 +23,7 @@ import android.graphics.RectF;
import com.android.systemui.Dumpable;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.util.ViewController;
@@ -44,6 +45,7 @@ abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
extends ViewController<T> implements Dumpable {
@NonNull final StatusBarStateController mStatusBarStateController;
@NonNull final PanelExpansionStateManager mPanelExpansionStateManager;
+ @NonNull final SystemUIDialogManager mDialogManager;
@NonNull final DumpManager mDumpManger;
boolean mNotificationShadeVisible;
@@ -52,10 +54,12 @@ abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
T view,
@NonNull StatusBarStateController statusBarStateController,
@NonNull PanelExpansionStateManager panelExpansionStateManager,
+ @NonNull SystemUIDialogManager dialogManager,
@NonNull DumpManager dumpManager) {
super(view);
mStatusBarStateController = statusBarStateController;
mPanelExpansionStateManager = panelExpansionStateManager;
+ mDialogManager = dialogManager;
mDumpManger = dumpManager;
}
@@ -64,12 +68,14 @@ abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
@Override
protected void onViewAttached() {
mPanelExpansionStateManager.addExpansionListener(mPanelExpansionListener);
+ mDialogManager.registerListener(mDialogListener);
mDumpManger.registerDumpable(getDumpTag(), this);
}
@Override
protected void onViewDetached() {
mPanelExpansionStateManager.removeExpansionListener(mPanelExpansionListener);
+ mDialogManager.registerListener(mDialogListener);
mDumpManger.unregisterDumpable(getDumpTag());
}
@@ -95,7 +101,8 @@ abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
* authentication.
*/
boolean shouldPauseAuth() {
- return mNotificationShadeVisible;
+ return mNotificationShadeVisible
+ || mDialogManager.shouldHideAffordance();
}
/**
@@ -189,4 +196,7 @@ abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
updatePauseAuth();
}
};
+
+ private final SystemUIDialogManager.Listener mDialogListener =
+ (shouldHide) -> updatePauseAuth();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java
index 894b29583cc9..3732100a2a06 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
/**
@@ -30,8 +31,10 @@ class UdfpsBpViewController extends UdfpsAnimationViewController<UdfpsBpView> {
@NonNull UdfpsBpView view,
@NonNull StatusBarStateController statusBarStateController,
@NonNull PanelExpansionStateManager panelExpansionStateManager,
+ @NonNull SystemUIDialogManager systemUIDialogManager,
@NonNull DumpManager dumpManager) {
- super(view, statusBarStateController, panelExpansionStateManager, dumpManager);
+ super(view, statusBarStateController, panelExpansionStateManager,
+ systemUIDialogManager, dumpManager);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 9808045d4ea8..3e9d6b0fa362 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -47,7 +47,6 @@ import android.os.RemoteException;
import android.os.Trace;
import android.os.VibrationEffect;
import android.os.Vibrator;
-import android.provider.Settings;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -71,6 +70,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -119,6 +119,7 @@ public class UdfpsController implements DozeReceiver {
@NonNull private final KeyguardStateController mKeyguardStateController;
@NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
@NonNull private final DumpManager mDumpManager;
+ @NonNull private final SystemUIDialogManager mDialogManager;
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Nullable private final Vibrator mVibrator;
@NonNull private final FalsingManager mFalsingManager;
@@ -165,9 +166,6 @@ public class UdfpsController implements DozeReceiver {
private boolean mAttemptedToDismissKeyguard;
private Set<Callback> mCallbacks = new HashSet<>();
- private static final int DEFAULT_TICK = VibrationEffect.Composition.PRIMITIVE_LOW_TICK;
- private final VibrationEffect mTick;
-
@VisibleForTesting
public static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
new AudioAttributes.Builder()
@@ -282,9 +280,6 @@ public class UdfpsController implements DozeReceiver {
return;
}
mGoodCaptureReceived = true;
- if (mVibrator != null) {
- mVibrator.cancel();
- }
mView.stopIllumination();
if (mServerRequest != null) {
mServerRequest.onAcquiredGood();
@@ -559,7 +554,8 @@ public class UdfpsController implements DozeReceiver {
@Main Handler mainHandler,
@NonNull ConfigurationController configurationController,
@NonNull SystemClock systemClock,
- @NonNull UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) {
+ @NonNull UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
+ @NonNull SystemUIDialogManager dialogManager) {
mContext = context;
mExecution = execution;
mVibrator = vibrator;
@@ -574,6 +570,7 @@ public class UdfpsController implements DozeReceiver {
mKeyguardStateController = keyguardStateController;
mKeyguardViewManager = statusBarKeyguardViewManager;
mDumpManager = dumpManager;
+ mDialogManager = dialogManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mFalsingManager = falsingManager;
mPowerManager = powerManager;
@@ -586,7 +583,6 @@ public class UdfpsController implements DozeReceiver {
mConfigurationController = configurationController;
mSystemClock = systemClock;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
- mTick = lowTick(context, false /* useShortRampup */, DEFAULT_VIBRATION_DURATION);
mSensorProps = findFirstUdfps();
// At least one UDFPS sensor exists
@@ -622,47 +618,6 @@ public class UdfpsController implements DozeReceiver {
}
/**
- * Returns the continuous low tick effect that starts playing on the udfps finger-down event.
- */
- public static VibrationEffect lowTick(
- Context context,
- boolean useShortRampUp,
- long duration
- ) {
- boolean useLowTickDefault = context.getResources()
- .getBoolean(R.bool.config_udfpsUseLowTick);
- int primitiveTick = DEFAULT_TICK;
- if (Settings.Global.getFloat(
- context.getContentResolver(),
- "tick-low", useLowTickDefault ? 1 : 0) == 0) {
- primitiveTick = VibrationEffect.Composition.PRIMITIVE_TICK;
- }
- float tickIntensity = Settings.Global.getFloat(
- context.getContentResolver(),
- "tick-intensity",
- context.getResources().getFloat(R.dimen.config_udfpsTickIntensity));
- int tickDelay = Settings.Global.getInt(
- context.getContentResolver(),
- "tick-delay",
- context.getResources().getInteger(R.integer.config_udfpsTickDelay));
-
- VibrationEffect.Composition composition = VibrationEffect.startComposition();
- composition.addPrimitive(primitiveTick, tickIntensity, 0);
- int primitives = (int) (duration / tickDelay);
- float[] rampUp = new float[]{.48f, .58f, .69f, .83f};
- if (useShortRampUp) {
- rampUp = new float[]{.5f, .7f};
- }
- for (int i = 0; i < rampUp.length; i++) {
- composition.addPrimitive(primitiveTick, tickIntensity * rampUp[i], tickDelay);
- }
- for (int i = rampUp.length; i < primitives; i++) {
- composition.addPrimitive(primitiveTick, tickIntensity, tickDelay);
- }
- return composition.compose();
- }
-
- /**
* Play haptic to signal udfps scanning started.
*/
@VisibleForTesting
@@ -671,8 +626,8 @@ public class UdfpsController implements DozeReceiver {
mVibrator.vibrate(
Process.myUid(),
mContext.getOpPackageName(),
- mTick,
- "udfps-onStart-tick",
+ EFFECT_CLICK,
+ "udfps-onStart-click",
VIBRATION_SONIFICATION_ATTRIBUTES);
}
}
@@ -864,6 +819,7 @@ public class UdfpsController implements DozeReceiver {
mServerRequest.mEnrollHelper,
mStatusBarStateController,
mPanelExpansionStateManager,
+ mDialogManager,
mDumpManager
);
case BiometricOverlayConstants.REASON_AUTH_KEYGUARD:
@@ -882,6 +838,7 @@ public class UdfpsController implements DozeReceiver {
mSystemClock,
mKeyguardStateController,
mUnlockedScreenOffAnimationController,
+ mDialogManager,
this
);
case BiometricOverlayConstants.REASON_AUTH_BP:
@@ -892,6 +849,7 @@ public class UdfpsController implements DozeReceiver {
bpView,
mStatusBarStateController,
mPanelExpansionStateManager,
+ mDialogManager,
mDumpManager
);
case BiometricOverlayConstants.REASON_AUTH_OTHER:
@@ -903,6 +861,7 @@ public class UdfpsController implements DozeReceiver {
authOtherView,
mStatusBarStateController,
mPanelExpansionStateManager,
+ mDialogManager,
mDumpManager
);
default:
@@ -1059,7 +1018,6 @@ public class UdfpsController implements DozeReceiver {
}
}
mOnFingerDown = false;
- mVibrator.cancel();
if (mView.isIlluminationRequested()) {
mView.stopIllumination();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
index 1f01fc5a4b3d..ac38b13cc4dd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
@@ -20,9 +20,7 @@ import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.content.res.TypedArray;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -30,7 +28,6 @@ import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
-import android.util.TypedValue;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.LinearInterpolator;
@@ -38,7 +35,6 @@ import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.internal.graphics.ColorUtils;
import com.android.systemui.R;
/**
@@ -106,9 +102,8 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
mSensorOutlinePaint = new Paint(0 /* flags */);
mSensorOutlinePaint.setAntiAlias(true);
- mSensorOutlinePaint.setColor(mContext.getColor(R.color.udfps_enroll_icon));
- mSensorOutlinePaint.setStyle(Paint.Style.STROKE);
- mSensorOutlinePaint.setStrokeWidth(2.f);
+ mSensorOutlinePaint.setColor(mContext.getColor(R.color.udfps_moving_target_fill));
+ mSensorOutlinePaint.setStyle(Paint.Style.FILL);
mBlueFill = new Paint(0 /* flags */);
mBlueFill.setAntiAlias(true);
@@ -117,12 +112,12 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
mMovingTargetFpIcon = context.getResources()
.getDrawable(R.drawable.ic_kg_fingerprint, null);
- mMovingTargetFpIcon.setTint(Color.WHITE);
+ mMovingTargetFpIcon.setTint(mContext.getColor(R.color.udfps_enroll_icon));
mMovingTargetFpIcon.mutate();
mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon));
- mHintColorFaded = getHintColorFaded(context);
+ mHintColorFaded = context.getColor(R.color.udfps_moving_target_fill);
mHintColorHighlight = context.getColor(R.color.udfps_enroll_progress);
mHintMaxWidthPx = Utils.dpToPixels(context, HINT_MAX_WIDTH_DP);
mHintPaddingPx = Utils.dpToPixels(context, HINT_PADDING_DP);
@@ -218,22 +213,6 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
};
}
- @ColorInt
- private static int getHintColorFaded(@NonNull Context context) {
- final TypedValue tv = new TypedValue();
- context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, tv, true);
- final int alpha = (int) (tv.getFloat() * 255f);
-
- final int[] attrs = new int[] {android.R.attr.colorControlNormal};
- final TypedArray ta = context.obtainStyledAttributes(attrs);
- try {
- @ColorInt final int color = ta.getColor(0, context.getColor(R.color.white_disabled));
- return ColorUtils.setAlphaComponent(color, alpha);
- } finally {
- ta.recycle();
- }
- }
-
void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) {
mEnrollHelper = helper;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
index 79c7e66d40f7..631a461b0627 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
@@ -18,12 +18,10 @@ package com.android.systemui.biometrics;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
-import android.util.TypedValue;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
@@ -80,24 +78,11 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable {
mBackgroundPaint = new Paint();
mBackgroundPaint.setStrokeWidth(mStrokeWidthPx);
- mBackgroundPaint.setColor(context.getColor(R.color.white_disabled));
+ mBackgroundPaint.setColor(context.getColor(R.color.udfps_moving_target_fill));
mBackgroundPaint.setAntiAlias(true);
mBackgroundPaint.setStyle(Paint.Style.STROKE);
mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND);
- // Set background paint color and alpha.
- final int[] attrs = new int[] {android.R.attr.colorControlNormal};
- final TypedArray typedArray = context.obtainStyledAttributes(attrs);
- try {
- @ColorInt final int tintColor = typedArray.getColor(0, mBackgroundPaint.getColor());
- mBackgroundPaint.setColor(tintColor);
- } finally {
- typedArray.recycle();
- }
- TypedValue alpha = new TypedValue();
- context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, alpha, true);
- mBackgroundPaint.setAlpha((int) (alpha.getFloat() * 255f));
-
// Progress fill should *not* use the extracted system color.
mFillPaint = new Paint();
mFillPaint.setStrokeWidth(mStrokeWidthPx);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
index 292a904af96e..ac9e92e22569 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
@@ -22,6 +22,7 @@ import android.graphics.PointF;
import com.android.systemui.R;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
/**
@@ -54,8 +55,10 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController<Udfp
@NonNull UdfpsEnrollHelper enrollHelper,
@NonNull StatusBarStateController statusBarStateController,
@NonNull PanelExpansionStateManager panelExpansionStateManager,
+ @NonNull SystemUIDialogManager systemUIDialogManager,
@NonNull DumpManager dumpManager) {
- super(view, statusBarStateController, panelExpansionStateManager, dumpManager);
+ super(view, statusBarStateController, panelExpansionStateManager, systemUIDialogManager,
+ dumpManager);
mEnrollProgressBarRadius = getContext().getResources()
.getInteger(R.integer.config_udfpsEnrollProgressBar);
mEnrollHelper = enrollHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java
index 619873367ee8..97dca0fbdedf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
/**
@@ -33,8 +34,10 @@ class UdfpsFpmOtherViewController extends UdfpsAnimationViewController<UdfpsFpmO
@NonNull UdfpsFpmOtherView view,
@NonNull StatusBarStateController statusBarStateController,
@NonNull PanelExpansionStateManager panelExpansionStateManager,
+ @NonNull SystemUIDialogManager systemUIDialogManager,
@NonNull DumpManager dumpManager) {
- super(view, statusBarStateController, panelExpansionStateManager, dumpManager);
+ super(view, statusBarStateController, panelExpansionStateManager, systemUIDialogManager,
+ dumpManager);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 8f4d6f6aa973..3e8a568cb803 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -31,6 +31,7 @@ import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
@@ -86,8 +87,10 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
@NonNull SystemClock systemClock,
@NonNull KeyguardStateController keyguardStateController,
@NonNull UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
+ @NonNull SystemUIDialogManager systemUIDialogManager,
@NonNull UdfpsController udfpsController) {
- super(view, statusBarStateController, panelExpansionStateManager, dumpManager);
+ super(view, statusBarStateController, panelExpansionStateManager, systemUIDialogManager,
+ dumpManager);
mKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockScreenShadeTransitionController = transitionController;
@@ -217,6 +220,10 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
return false;
}
+ if (mDialogManager.shouldHideAffordance()) {
+ return true;
+ }
+
if (mLaunchTransitionFadingAway) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index d3d6e03c9bc7..6f30ac3901e1 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -18,6 +18,7 @@ package com.android.systemui.controls.ui
import android.annotation.MainThread
import android.app.Dialog
+import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
@@ -88,7 +89,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
bouncerOrRun(createAction(cvh.cws.ci.controlId, {
cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
if (cvh.usePanel()) {
- showDetail(cvh, control.getAppIntent().getIntent())
+ showDetail(cvh, control.getAppIntent())
} else {
cvh.action(CommandAction(templateId))
}
@@ -116,7 +117,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
// Long press snould only be called when there is valid control state, otherwise ignore
cvh.cws.control?.let {
cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
- showDetail(cvh, it.getAppIntent().getIntent())
+ showDetail(cvh, it.getAppIntent())
}
}, false /* blockable */))
}
@@ -167,10 +168,10 @@ class ControlActionCoordinatorImpl @Inject constructor(
bgExecutor.execute { vibrator.vibrate(effect) }
}
- private fun showDetail(cvh: ControlViewHolder, intent: Intent) {
+ private fun showDetail(cvh: ControlViewHolder, pendingIntent: PendingIntent) {
bgExecutor.execute {
val activities: List<ResolveInfo> = context.packageManager.queryIntentActivities(
- intent,
+ pendingIntent.getIntent(),
PackageManager.MATCH_DEFAULT_ONLY
)
@@ -178,7 +179,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
// make sure the intent is valid before attempting to open the dialog
if (activities.isNotEmpty() && taskViewFactory.isPresent) {
taskViewFactory.get().create(context, uiExecutor, {
- dialog = DetailDialog(activityContext, it, intent, cvh).also {
+ dialog = DetailDialog(activityContext, it, pendingIntent, cvh).also {
it.setOnDismissListener { _ -> dialog = null }
it.show()
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index 8a47a36de8c4..4758ab04e2e5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -43,7 +43,7 @@ import com.android.wm.shell.TaskView
class DetailDialog(
val activityContext: Context?,
val taskView: TaskView,
- val intent: Intent,
+ val pendingIntent: PendingIntent,
val cvh: ControlViewHolder
) : Dialog(
activityContext ?: cvh.context,
@@ -59,6 +59,14 @@ class DetailDialog(
var detailTaskId = INVALID_TASK_ID
+ private val fillInIntent = Intent().apply {
+ putExtra(EXTRA_USE_PANEL, true)
+
+ // Apply flags to make behaviour match documentLaunchMode=always.
+ addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
+ addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
+ }
+
fun removeDetailTask() {
if (detailTaskId == INVALID_TASK_ID) return
ActivityTaskManager.getInstance().removeTask(detailTaskId)
@@ -67,13 +75,6 @@ class DetailDialog(
val stateCallback = object : TaskView.Listener {
override fun onInitialized() {
- val launchIntent = Intent(intent)
- launchIntent.putExtra(EXTRA_USE_PANEL, true)
-
- // Apply flags to make behaviour match documentLaunchMode=always.
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
-
val options = activityContext?.let {
ActivityOptions.makeCustomAnimation(
it,
@@ -82,9 +83,8 @@ class DetailDialog(
)
} ?: ActivityOptions.makeBasic()
taskView.startActivity(
- PendingIntent.getActivity(context, 0, launchIntent,
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE),
- null /* fillInIntent */,
+ pendingIntent,
+ fillInIntent,
options,
getTaskViewBounds()
)
@@ -97,6 +97,9 @@ class DetailDialog(
override fun onTaskCreated(taskId: Int, name: ComponentName?) {
detailTaskId = taskId
+ requireViewById<ViewGroup>(R.id.controls_activity_view).apply {
+ setAlpha(1f)
+ }
}
override fun onReleased() {
@@ -121,6 +124,7 @@ class DetailDialog(
requireViewById<ViewGroup>(R.id.controls_activity_view).apply {
addView(taskView)
+ setAlpha(0f)
}
requireViewById<ImageView>(R.id.control_detail_close).apply {
@@ -134,7 +138,7 @@ class DetailDialog(
removeDetailTask()
dismiss()
context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
- v.context.startActivity(intent)
+ pendingIntent.send()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index c5d3a70676d0..d950d6d8c07e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -31,6 +31,7 @@ import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.TaskViewFactory;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.bubbles.Bubbles;
+import com.android.wm.shell.compatui.CompatUI;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
@@ -38,7 +39,6 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.recents.RecentTasks;
-import com.android.wm.shell.sizecompatui.SizeCompatUI;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
@@ -110,7 +110,7 @@ public interface SysUIComponent {
Builder setRecentTasks(Optional<RecentTasks> r);
@BindsInstance
- Builder setSizeCompatUI(Optional<SizeCompatUI> s);
+ Builder setCompatUI(Optional<CompatUI> s);
@BindsInstance
Builder setDragAndDrop(Optional<DragAndDrop> d);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 90a3ad225f51..b815d4e9884b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -25,6 +25,7 @@ import com.android.wm.shell.ShellInit;
import com.android.wm.shell.TaskViewFactory;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.bubbles.Bubbles;
+import com.android.wm.shell.compatui.CompatUI;
import com.android.wm.shell.dagger.TvWMShellModule;
import com.android.wm.shell.dagger.WMShellModule;
import com.android.wm.shell.dagger.WMSingleton;
@@ -35,7 +36,6 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.recents.RecentTasks;
-import com.android.wm.shell.sizecompatui.SizeCompatUI;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
@@ -119,7 +119,7 @@ public interface WMComponent {
Optional<RecentTasks> getRecentTasks();
@WMSingleton
- SizeCompatUI getSizeCompatUI();
+ CompatUI getCompatUI();
@WMSingleton
DragAndDrop getDragAndDrop();
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index ff14064834d7..2ebcd8531128 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -121,6 +121,7 @@ import com.android.systemui.scrim.ScrimDrawable;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.telephony.TelephonyListenerManager;
@@ -236,6 +237,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
protected Handler mMainHandler;
private int mSmallestScreenWidthDp;
private final Optional<StatusBar> mStatusBarOptional;
+ private final SystemUIDialogManager mDialogManager;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final DialogLaunchAnimator mDialogLaunchAnimator;
@@ -346,7 +348,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
PackageManager packageManager,
Optional<StatusBar> statusBarOptional,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- DialogLaunchAnimator dialogLaunchAnimator) {
+ DialogLaunchAnimator dialogLaunchAnimator,
+ SystemUIDialogManager dialogManager) {
mContext = context;
mWindowManagerFuncs = windowManagerFuncs;
mAudioManager = audioManager;
@@ -378,6 +381,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
mStatusBarOptional = statusBarOptional;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mDialogLaunchAnimator = dialogLaunchAnimator;
+ mDialogManager = dialogManager;
// receive broadcasts
IntentFilter filter = new IntentFilter();
@@ -677,7 +681,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
mAdapter, mOverflowAdapter, mSysuiColorExtractor,
mStatusBarService, mNotificationShadeWindowController,
mSysUiState, this::onRefresh, mKeyguardShowing, mPowerAdapter, mUiEventLogger,
- mStatusBarOptional, mKeyguardUpdateMonitor, mLockPatternUtils);
+ mStatusBarOptional, mKeyguardUpdateMonitor, mLockPatternUtils,
+ mDialogManager);
dialog.setOnDismissListener(this);
dialog.setOnShowListener(this);
@@ -2219,10 +2224,12 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
SysUiState sysuiState, Runnable onRefreshCallback, boolean keyguardShowing,
MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger,
Optional<StatusBar> statusBarOptional,
- KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils) {
+ KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils,
+ SystemUIDialogManager systemUiDialogManager) {
// We set dismissOnDeviceLock to false because we have a custom broadcast receiver to
// dismiss this dialog when the device is locked.
- super(context, themeRes, false /* dismissOnDeviceLock */);
+ super(context, themeRes, false /* dismissOnDeviceLock */,
+ systemUiDialogManager);
mContext = context;
mAdapter = adapter;
mOverflowAdapter = overflowAdapter;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 8d0733645117..89a5d72a3ca4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2090,6 +2090,15 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
private final Runnable mKeyguardGoingAwayRunnable = new Runnable() {
@Override
public void run() {
+ // If the keyguard is already going away, or it's about to because we are going to
+ // trigger the going-away remote animation to show the surface behind, don't do it
+ // again. That will cause the current animation to be cancelled unnecessarily.
+ if (mKeyguardStateController.isKeyguardGoingAway()
+ || mSurfaceBehindRemoteAnimationRequested
+ || mSurfaceBehindRemoteAnimationRunning) {
+ return;
+ }
+
Trace.beginSection("KeyguardViewMediator.mKeyGuardGoingAwayRunnable");
if (DEBUG) Log.d(TAG, "keyguardGoingAway");
mKeyguardViewControllerLazy.get().keyguardGoingAway();
@@ -2451,9 +2460,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
if (mSurfaceBehindRemoteAnimationFinishedCallback != null) {
try {
- if (!cancelled) {
- mSurfaceBehindRemoteAnimationFinishedCallback.onAnimationFinished();
- }
+ mSurfaceBehindRemoteAnimationFinishedCallback.onAnimationFinished();
mSurfaceBehindRemoteAnimationFinishedCallback = null;
} catch (RemoteException e) {
e.printStackTrace();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index c12d48d225ae..f2cb254c3b97 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -44,6 +44,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
/**
* Base dialog for media output UI
@@ -52,6 +53,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
MediaOutputController.Callback, Window.Callback {
private static final String TAG = "MediaOutputDialog";
+ private static final String EMPTY_TITLE = " ";
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
private final RecyclerView.LayoutManager mLayoutManager;
@@ -82,9 +84,12 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
}
};
- public MediaOutputBaseDialog(Context context, MediaOutputController mediaOutputController) {
- super(context);
- mContext = context;
+ public MediaOutputBaseDialog(Context context, MediaOutputController mediaOutputController,
+ SystemUIDialogManager dialogManager) {
+ super(context, dialogManager);
+
+ // Save the context that is wrapped with our theme.
+ mContext = getContext();
mMediaOutputController = mediaOutputController;
mLayoutManager = new LinearLayoutManager(mContext);
mListMaxHeight = context.getResources().getDimensionPixelSize(
@@ -105,6 +110,9 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
lp.setFitInsetsIgnoringVisibility(true);
window.setAttributes(lp);
window.setContentView(mDialogView);
+ // Sets window to a blank string to avoid talkback announce app label first when pop up,
+ // which doesn't make sense.
+ window.setTitle(EMPTY_TITLE);
mHeaderTitle = mDialogView.requireViewById(R.id.header_title);
mHeaderSubtitle = mDialogView.requireViewById(R.id.header_subtitle);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index ad6901f40d6b..a1e2c57c5c37 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -56,6 +56,7 @@ import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import java.util.ArrayList;
import java.util.Collection;
@@ -80,6 +81,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
private final ShadeController mShadeController;
private final ActivityStarter mActivityStarter;
private final DialogLaunchAnimator mDialogLaunchAnimator;
+ private final SystemUIDialogManager mDialogManager;
private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
private final boolean mAboveStatusbar;
private final boolean mVolumeAdjustmentForRemoteGroupSessions;
@@ -101,7 +103,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
boolean aboveStatusbar, MediaSessionManager mediaSessionManager, LocalBluetoothManager
lbm, ShadeController shadeController, ActivityStarter starter,
NotificationEntryManager notificationEntryManager, UiEventLogger uiEventLogger,
- DialogLaunchAnimator dialogLaunchAnimator) {
+ DialogLaunchAnimator dialogLaunchAnimator, SystemUIDialogManager dialogManager) {
mContext = context;
mPackageName = packageName;
mMediaSessionManager = mediaSessionManager;
@@ -117,6 +119,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
mDialogLaunchAnimator = dialogLaunchAnimator;
mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
+ mDialogManager = dialogManager;
}
void start(@NonNull Callback cb) {
@@ -478,9 +481,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
// We show the output group dialog from the output dialog.
MediaOutputController controller = new MediaOutputController(mContext, mPackageName,
mAboveStatusbar, mMediaSessionManager, mLocalBluetoothManager, mShadeController,
- mActivityStarter, mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
+ mActivityStarter, mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator,
+ mDialogManager);
MediaOutputGroupDialog dialog = new MediaOutputGroupDialog(mContext, mAboveStatusbar,
- controller);
+ controller, mDialogManager);
mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index eca8ac90427b..7e2558ceb1e8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -28,6 +28,7 @@ import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
/**
* Dialog for media output transferring.
@@ -37,8 +38,9 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
final UiEventLogger mUiEventLogger;
MediaOutputDialog(Context context, boolean aboveStatusbar, MediaOutputController
- mediaOutputController, UiEventLogger uiEventLogger) {
- super(context, mediaOutputController);
+ mediaOutputController, UiEventLogger uiEventLogger,
+ SystemUIDialogManager dialogManager) {
+ super(context, mediaOutputController, dialogManager);
mUiEventLogger = uiEventLogger;
mAdapter = new MediaOutputAdapter(mMediaOutputController, this);
if (!aboveStatusbar) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
index b91901de5af3..a7bc85256fcd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -25,6 +25,7 @@ import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.phone.ShadeController
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
import javax.inject.Inject
/**
@@ -38,7 +39,8 @@ class MediaOutputDialogFactory @Inject constructor(
private val starter: ActivityStarter,
private val notificationEntryManager: NotificationEntryManager,
private val uiEventLogger: UiEventLogger,
- private val dialogLaunchAnimator: DialogLaunchAnimator
+ private val dialogLaunchAnimator: DialogLaunchAnimator,
+ private val dialogManager: SystemUIDialogManager
) {
companion object {
var mediaOutputDialog: MediaOutputDialog? = null
@@ -51,8 +53,9 @@ class MediaOutputDialogFactory @Inject constructor(
val controller = MediaOutputController(context, packageName, aboveStatusBar,
mediaSessionManager, lbm, shadeController, starter, notificationEntryManager,
- uiEventLogger, dialogLaunchAnimator)
- val dialog = MediaOutputDialog(context, aboveStatusBar, controller, uiEventLogger)
+ uiEventLogger, dialogLaunchAnimator, dialogManager)
+ val dialog = MediaOutputDialog(context, aboveStatusBar, controller, uiEventLogger,
+ dialogManager)
mediaOutputDialog = dialog
// Show the dialog.
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
index b41e8137c1ec..478b890bf92d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
@@ -25,6 +25,7 @@ import android.widget.LinearLayout;
import androidx.core.graphics.drawable.IconCompat;
import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
/**
* Dialog for media output group.
@@ -32,8 +33,8 @@ import com.android.systemui.R;
public class MediaOutputGroupDialog extends MediaOutputBaseDialog {
MediaOutputGroupDialog(Context context, boolean aboveStatusbar, MediaOutputController
- mediaOutputController) {
- super(context, mediaOutputController);
+ mediaOutputController, SystemUIDialogManager dialogManager) {
+ super(context, mediaOutputController, dialogManager);
mMediaOutputController.resetGroupMediaDevices();
mAdapter = new MediaOutputGroupAdapter(mMediaOutputController);
if (!aboveStatusbar) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 03bceacdfbdc..7a12ecc097a2 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -1252,6 +1252,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private void onImeSwitcherClick(View v) {
mInputMethodManager.showInputMethodPickerFromSystem(
true /* showAuxiliarySubtypes */, mDisplayId);
+ mUiEventLogger.log(KeyButtonView.NavBarButtonEvent.NAVBAR_IME_SWITCHER_BUTTON_TAP);
};
private boolean onLongPressBackHome(View v) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
index debd2ebb51be..d27b71673ce5 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
@@ -96,6 +96,9 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
@UiEvent(doc = "The overview button was pressed in the navigation bar.")
NAVBAR_OVERVIEW_BUTTON_TAP(535),
+ @UiEvent(doc = "The ime switcher button was pressed in the navigation bar.")
+ NAVBAR_IME_SWITCHER_BUTTON_TAP(923),
+
@UiEvent(doc = "The home button was long-pressed in the navigation bar.")
NAVBAR_HOME_BUTTON_LONGPRESS(536),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index 7ba9cc22bec9..a2577d6e7f60 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -98,7 +98,7 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements
toggleDataSaver();
Prefs.putBoolean(mContext, Prefs.Key.QS_DATA_SAVER_DIALOG_SHOWN, true);
});
- dialog.setNegativeButton(com.android.internal.R.string.cancel, null);
+ dialog.setNeutralButton(com.android.internal.R.string.cancel, null);
dialog.setShowForAllUsers(true);
if (view != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 20805a141312..a339dcf73f74 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -190,7 +190,6 @@ public class DndTile extends QSTileImpl<BooleanState> {
case Settings.Secure.ZEN_DURATION_PROMPT:
mUiHandler.post(() -> {
Dialog dialog = makeZenModeDialog();
- SystemUIDialog.registerDismissListener(dialog);
if (view != null) {
mDialogLaunchAnimator.showFromView(dialog, view, false);
} else {
@@ -211,10 +210,12 @@ public class DndTile extends QSTileImpl<BooleanState> {
}
private Dialog makeZenModeDialog() {
- AlertDialog dialog = new EnableZenModeDialog(mContext, R.style.Theme_SystemUI_Dialog)
- .createDialog();
+ AlertDialog dialog = new EnableZenModeDialog(mContext, R.style.Theme_SystemUI_Dialog,
+ true /* cancelIsNeutral */).createDialog();
SystemUIDialog.applyFlags(dialog);
SystemUIDialog.setShowForAllUsers(dialog, true);
+ SystemUIDialog.registerDismissListener(dialog);
+ SystemUIDialog.setDialogSize(dialog);
return dialog;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index ba4257f52892..2a398496af77 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -159,7 +159,9 @@ public class InternetDialog extends SystemUIDialog implements
if (DEBUG) {
Log.d(TAG, "Init InternetDialog");
}
- mContext = context;
+
+ // Save the context that is wrapped with our theme.
+ mContext = getContext();
mHandler = handler;
mBackgroundExecutor = executor;
mInternetDialogFactory = internetDialogFactory;
@@ -301,15 +303,11 @@ public class InternetDialog extends SystemUIDialog implements
if (DEBUG) {
Log.d(TAG, "updateDialog");
}
- if (mInternetDialogController.isAirplaneModeEnabled()) {
- mInternetDialogSubTitle.setVisibility(View.GONE);
- mAirplaneModeLayout.setVisibility(View.VISIBLE);
- } else {
- mInternetDialogTitle.setText(getDialogTitleText());
- mInternetDialogSubTitle.setVisibility(View.VISIBLE);
- mInternetDialogSubTitle.setText(getSubtitleText());
- mAirplaneModeLayout.setVisibility(View.GONE);
- }
+ mInternetDialogTitle.setText(getDialogTitleText());
+ mInternetDialogSubTitle.setText(getSubtitleText());
+ mAirplaneModeLayout.setVisibility(
+ mInternetDialogController.isAirplaneModeEnabled() ? View.VISIBLE : View.GONE);
+
updateEthernet();
if (shouldUpdateMobileNetwork) {
setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular(),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index 1fee1b430073..4908d4fb214e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -316,15 +316,11 @@ public class InternetDialogController implements AccessPointController.AccessPoi
}
CharSequence getSubtitleText(boolean isProgressBarVisible) {
- if (isAirplaneModeEnabled()) {
- return null;
- }
-
if (mCanConfigWifi && !mWifiManager.isWifiEnabled()) {
- // When the airplane mode is off and Wi-Fi is disabled.
+ // When Wi-Fi is disabled.
// Sub-Title: Wi-Fi is off
if (DEBUG) {
- Log.d(TAG, "Airplane mode off + Wi-Fi off.");
+ Log.d(TAG, "Wi-Fi off.");
}
return mContext.getText(SUBTITLE_TEXT_WIFI_IS_OFF);
}
@@ -882,10 +878,8 @@ public class InternetDialogController implements AccessPointController.AccessPoi
if (accessPoints == null || accessPoints.size() == 0) {
mConnectedEntry = null;
mWifiEntriesCount = 0;
- if (mCallback != null) {
- mCallback.onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry */,
- false /* hasMoreEntry */);
- }
+ mCallback.onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry */,
+ false /* hasMoreEntry */);
return;
}
@@ -917,9 +911,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi
mConnectedEntry = connectedEntry;
mWifiEntriesCount = wifiEntries.size();
- if (mCallback != null) {
- mCallback.onAccessPointsChanged(wifiEntries, mConnectedEntry, hasMoreEntry);
- }
+ mCallback.onAccessPointsChanged(wifiEntries, mConnectedEntry, hasMoreEntry);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 3ed7e84af020..e7cd1e2dab3c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -76,6 +76,7 @@ import androidx.annotation.NonNull;
import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.util.ScreenshotHelper;
import com.android.systemui.Dumpable;
@@ -88,6 +89,7 @@ import com.android.systemui.navigationbar.NavigationBar;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.navigationbar.buttons.KeyButtonView;
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.shared.recents.IOverviewProxy;
@@ -161,6 +163,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
private final Optional<StartingSurface> mStartingSurface;
private final SmartspaceTransitionController mSmartspaceTransitionController;
private final Optional<RecentTasks> mRecentTasks;
+ private final UiEventLogger mUiEventLogger;
private Region mActiveNavBarRegion;
@@ -248,6 +251,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
mContext.getSystemService(InputMethodManager.class)
.showInputMethodPickerFromSystem(true /* showAuxiliarySubtypes */,
DEFAULT_DISPLAY);
+ mUiEventLogger.log(KeyButtonView.NavBarButtonEvent.NAVBAR_IME_SWITCHER_BUTTON_TAP);
}
@Override
@@ -560,6 +564,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
ShellTransitions shellTransitions,
ScreenLifecycle screenLifecycle,
SmartspaceTransitionController smartspaceTransitionController,
+ UiEventLogger uiEventLogger,
DumpManager dumpManager) {
super(broadcastDispatcher);
mContext = context;
@@ -581,6 +586,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
mOneHandedOptional = oneHandedOptional;
mShellTransitions = shellTransitions;
mRecentTasks = recentTasks;
+ mUiEventLogger = uiEventLogger;
// Assumes device always starts with back button until launcher tells it that it does not
mNavBarButtonAlpha = 1.0f;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 85bf98c09f59..7f130cb203c0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -16,6 +16,7 @@
package com.android.systemui.recents;
+import static com.android.systemui.shared.recents.utilities.Utilities.isTablet;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
@@ -248,8 +249,8 @@ public class ScreenPinningRequest implements View.OnClickListener,
.setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
View buttons = mLayout.findViewById(R.id.screen_pinning_buttons);
WindowManagerWrapper wm = WindowManagerWrapper.getInstance();
- if (!QuickStepContract.isGesturalMode(mNavBarMode)
- && wm.hasSoftNavigationBar(mContext.getDisplayId())) {
+ if (!QuickStepContract.isGesturalMode(mNavBarMode)
+ && wm.hasSoftNavigationBar(mContext.getDisplayId()) && !isTablet(mContext)) {
buttons.setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
swapChildrenIfRtlAndVertical(buttons);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index f43d9c350d62..d7b4738340e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -887,7 +887,13 @@ public class KeyguardIndicationController {
mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
}
} else {
- showBiometricMessage(mContext.getString(R.string.keyguard_unlock));
+ if (mKeyguardUpdateMonitor.isUdfpsSupported()
+ && mKeyguardUpdateMonitor.getUserCanSkipBouncer(
+ KeyguardUpdateMonitor.getCurrentUser())) {
+ showBiometricMessage(mContext.getString(R.string.keyguard_unlock_press));
+ } else {
+ showBiometricMessage(mContext.getString(R.string.keyguard_unlock));
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/UserUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/UserUtil.java
index c4fadff16c09..4551807499ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/UserUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/UserUtil.java
@@ -40,7 +40,7 @@ public class UserUtil {
super(context);
setTitle(R.string.user_remove_user_title);
setMessage(context.getString(R.string.user_remove_user_message));
- setButton(DialogInterface.BUTTON_NEGATIVE,
+ setButton(DialogInterface.BUTTON_NEUTRAL,
context.getString(android.R.string.cancel), this);
setButton(DialogInterface.BUTTON_POSITIVE,
context.getString(R.string.user_remove_user_remove), this);
@@ -51,7 +51,7 @@ public class UserUtil {
@Override
public void onClick(DialogInterface dialog, int which) {
- if (which == BUTTON_NEGATIVE) {
+ if (which == BUTTON_NEUTRAL) {
cancel();
} else {
dismiss();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt
new file mode 100644
index 000000000000..a1d086b5d768
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2021 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.charging
+
+import android.graphics.Color
+import android.graphics.PointF
+import android.graphics.RuntimeShader
+import android.util.MathUtils
+
+/**
+ * Shader class that renders a distorted ripple for the UDFPS dwell effect.
+ * Adjustable shader parameters:
+ * - progress
+ * - origin
+ * - color
+ * - time
+ * - maxRadius
+ * - distortionStrength.
+ * See per field documentation for more details.
+ *
+ * Modeled after frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java.
+ */
+class DwellRippleShader internal constructor() : RuntimeShader(SHADER, false) {
+ companion object {
+ private const val SHADER_UNIFORMS = """uniform vec2 in_origin;
+ uniform float in_time;
+ uniform float in_radius;
+ uniform float in_blur;
+ uniform vec4 in_color;
+ uniform float in_phase1;
+ uniform float in_phase2;
+ uniform float in_distortion_strength;"""
+ private const val SHADER_LIB = """
+ float softCircle(vec2 uv, vec2 xy, float radius, float blur) {
+ float blurHalf = blur * 0.5;
+ float d = distance(uv, xy);
+ return 1. - smoothstep(1. - blurHalf, 1. + blurHalf, d / radius);
+ }
+
+ float softRing(vec2 uv, vec2 xy, float radius, float blur) {
+ float thickness_half = radius * 0.25;
+ float circle_outer = softCircle(uv, xy, radius + thickness_half, blur);
+ float circle_inner = softCircle(uv, xy, radius - thickness_half, blur);
+ return circle_outer - circle_inner;
+ }
+
+ vec2 distort(vec2 p, float time, float distort_amount_xy, float frequency) {
+ return p + vec2(sin(p.x * frequency + in_phase1),
+ cos(p.y * frequency * 1.23 + in_phase2)) * distort_amount_xy;
+ }
+
+ vec4 ripple(vec2 p, float distort_xy, float frequency) {
+ vec2 p_distorted = distort(p, in_time, distort_xy, frequency);
+ float circle = softCircle(p_distorted, in_origin, in_radius * 1.2, in_blur);
+ float rippleAlpha = max(circle,
+ softRing(p_distorted, in_origin, in_radius, in_blur)) * 0.25;
+ return in_color * rippleAlpha;
+ }
+ """
+ private const val SHADER_MAIN = """vec4 main(vec2 p) {
+ vec4 color1 = ripple(p,
+ 12 * in_distortion_strength, // distort_xy
+ 0.012 // frequency
+ );
+ vec4 color2 = ripple(p,
+ 17.5 * in_distortion_strength, // distort_xy
+ 0.018 // frequency
+ );
+ // Alpha blend between two layers.
+ return vec4(color1.xyz + color2.xyz
+ * (1 - color1.w), color1.w + color2.w * (1-color1.w));
+ }"""
+ private const val SHADER = SHADER_UNIFORMS + SHADER_LIB + SHADER_MAIN
+ }
+
+ /**
+ * Maximum radius of the ripple.
+ */
+ var maxRadius: Float = 0.0f
+
+ /**
+ * Origin coordinate of the ripple.
+ */
+ var origin: PointF = PointF()
+ set(value) {
+ field = value
+ setUniform("in_origin", floatArrayOf(value.x, value.y))
+ }
+
+ /**
+ * Progress of the ripple. Float value between [0, 1].
+ */
+ var progress: Float = 0.0f
+ set(value) {
+ field = value
+ setUniform("in_radius",
+ (1 - (1 - value) * (1 - value) * (1 - value))* maxRadius)
+ setUniform("in_blur", MathUtils.lerp(1f, 0.7f, value))
+ }
+
+ /**
+ * Distortion strength between [0, 1], with 0 being no distortion and 1 being full distortion.
+ */
+ var distortionStrength: Float = 0.0f
+ set(value) {
+ field = value
+ setUniform("in_distortion_strength", value)
+ }
+
+ /**
+ * Play time since the start of the effect in seconds.
+ */
+ var time: Float = 0.0f
+ set(value) {
+ field = value * 0.001f
+ setUniform("in_time", field)
+ setUniform("in_phase1", field * 2f + 0.367f)
+ setUniform("in_phase2", field * 5.2f * 1.531f)
+ }
+
+ /**
+ * A hex value representing the ripple color, in the format of ARGB
+ */
+ var color: Int = 0xffffff.toInt()
+ set(value) {
+ field = value
+ val color = Color.valueOf(value)
+ setUniform("in_color", floatArrayOf(color.red(),
+ color.green(), color.blue(), color.alpha()))
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 2eb20654716d..63cb4ae39a58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -579,14 +579,24 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
if (contentView.hasOverlappingRendering()) {
int layerType = contentAlpha == 0.0f || contentAlpha == 1.0f ? LAYER_TYPE_NONE
: LAYER_TYPE_HARDWARE;
- int currentLayerType = contentView.getLayerType();
- if (currentLayerType != layerType) {
- contentView.setLayerType(layerType, null);
- }
+ contentView.setLayerType(layerType, null);
}
contentView.setAlpha(contentAlpha);
+ // After updating the current view, reset all views.
+ if (contentAlpha == 1f) {
+ resetAllContentAlphas();
+ }
}
+ /**
+ * If a subclass's {@link #getContentView()} returns different views depending on state,
+ * this method is an opportunity to reset the alpha of ALL content views, not just the
+ * current one, which may prevent a content view that is temporarily hidden from being reset.
+ *
+ * This should setAlpha(1.0f) and setLayerType(LAYER_TYPE_NONE) for all content views.
+ */
+ protected void resetAllContentAlphas() {}
+
@Override
protected void applyRoundness() {
super.applyRoundness();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 23a0a750561c..819f5a3f6dc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -2130,15 +2130,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
public void setExpandAnimationRunning(boolean expandAnimationRunning) {
- View contentView;
- if (mIsSummaryWithChildren) {
- contentView = mChildrenContainer;
- } else {
- contentView = getShowingLayout();
- }
- if (mGuts != null && mGuts.isExposed()) {
- contentView = mGuts;
- }
if (expandAnimationRunning) {
setAboveShelf(true);
mExpandAnimationRunning = true;
@@ -2151,9 +2142,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
if (mGuts != null) {
mGuts.setAlpha(1.0f);
}
- if (contentView != null) {
- contentView.setAlpha(1.0f);
- }
+ resetAllContentAlphas();
setExtraWidthForClipping(0.0f);
if (mNotificationParent != null) {
mNotificationParent.setExtraWidthForClipping(0.0f);
@@ -2601,10 +2590,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mPrivateLayout.animate().cancel();
if (mChildrenContainer != null) {
mChildrenContainer.animate().cancel();
- mChildrenContainer.setAlpha(1f);
}
- mPublicLayout.setAlpha(1f);
- mPrivateLayout.setAlpha(1f);
+ resetAllContentAlphas();
mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
updateChildrenVisibility();
} else {
@@ -2631,7 +2618,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
.alpha(0f)
.setStartDelay(delay)
.setDuration(duration)
- .withEndAction(() -> hiddenView.setVisibility(View.INVISIBLE));
+ .withEndAction(() -> {
+ hiddenView.setVisibility(View.INVISIBLE);
+ resetAllContentAlphas();
+ });
}
for (View showView : shownChildren) {
showView.setVisibility(View.VISIBLE);
@@ -2754,12 +2744,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
if (wasAppearing) {
// During the animation the visible view might have changed, so let's make sure all
// alphas are reset
- if (mChildrenContainer != null) {
- mChildrenContainer.setAlpha(1.0f);
- }
- for (NotificationContentView l : mLayouts) {
- l.setAlpha(1.0f);
- }
+ resetAllContentAlphas();
if (FADE_LAYER_OPTIMIZATION_ENABLED) {
setNotificationFaded(false);
} else {
@@ -2770,6 +2755,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
+ @Override
+ protected void resetAllContentAlphas() {
+ mPrivateLayout.setAlpha(1f);
+ mPrivateLayout.setLayerType(LAYER_TYPE_NONE, null);
+ mPublicLayout.setAlpha(1f);
+ mPublicLayout.setLayerType(LAYER_TYPE_NONE, null);
+ if (mChildrenContainer != null) {
+ mChildrenContainer.setAlpha(1f);
+ mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null);
+ }
+ }
+
/** Gets the last value set with {@link #setNotificationFaded(boolean)} */
@Override
public boolean isNotificationFaded() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index a9cc3237d719..e65846865ef8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -59,6 +59,7 @@ public class AmbientState {
private float mMaxHeadsUpTranslation;
private boolean mDismissAllInProgress;
private int mLayoutMinHeight;
+ private int mLayoutMaxHeight;
private NotificationShelf mShelf;
private int mZDistanceBetweenElements;
private int mBaseZHeight;
@@ -326,6 +327,14 @@ public class AmbientState {
mLayoutHeight = layoutHeight;
}
+ public void setLayoutMaxHeight(int maxLayoutHeight) {
+ mLayoutMaxHeight = maxLayoutHeight;
+ }
+
+ public int getLayoutMaxHeight() {
+ return mLayoutMaxHeight;
+ }
+
public float getTopPadding() {
return mTopPadding;
}
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 9167b08ecd0c..16c9fa79f24c 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
@@ -1110,6 +1110,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
private void updateAlgorithmHeightAndPadding() {
mAmbientState.setLayoutHeight(getLayoutHeight());
+ mAmbientState.setLayoutMaxHeight(mMaxLayoutHeight);
updateAlgorithmLayoutMinHeight();
mAmbientState.setTopPadding(mTopPadding);
}
@@ -3985,6 +3986,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
updateChronometers();
requestChildrenUpdate();
updateUseRoundedRectClipping();
+ updateDismissBehavior();
}
}
@@ -4931,6 +4933,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
StringBuilder sb = new StringBuilder("[")
.append(this.getClass().getSimpleName()).append(":")
.append(" pulsing=").append(mPulsing ? "T" : "f")
+ .append(" expanded=").append(mIsExpanded ? "T" : "f")
+ .append(" headsUpPinned=").append(mInHeadsUpPinnedMode ? "T" : "f")
+ .append(" qsClipping=").append(mShouldUseRoundedRectClipping ? "T" : "f")
+ .append(" qsClipDismiss=").append(mDismissUsingRowTranslationX ? "T" : "f")
.append(" visibility=").append(DumpUtilsKt.visibilityString(getVisibility()))
.append(" alpha=").append(getAlpha())
.append(" scrollY=").append(mAmbientState.getScrollY())
@@ -5458,7 +5464,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
// On the split keyguard, dismissing with clipping without a visual boundary looks odd,
// so let's use the content dismiss behavior instead.
boolean dismissUsingRowTranslationX = !mShouldUseSplitNotificationShade
- || mStatusBarState != StatusBarState.KEYGUARD;
+ || (mStatusBarState != StatusBarState.KEYGUARD && mIsExpanded);
if (mDismissUsingRowTranslationX != dismissUsingRowTranslationX) {
mDismissUsingRowTranslationX = dismissUsingRowTranslationX;
for (int i = 0; i < getChildCount(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 015edb8e5541..2c70a5fd9ce7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -29,6 +29,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.R;
import com.android.systemui.animation.ShadeInterpolation;
+import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -60,6 +61,7 @@ public class StackScrollAlgorithm {
@VisibleForTesting float mHeadsUpInset;
private int mPinnedZTranslationExtra;
private float mNotificationScrimPadding;
+ private int mCloseHandleUnderlapHeight;
public StackScrollAlgorithm(
Context context,
@@ -85,6 +87,7 @@ public class StackScrollAlgorithm {
R.dimen.heads_up_pinned_elevation);
mGapHeight = res.getDimensionPixelSize(R.dimen.notification_section_divider_height);
mNotificationScrimPadding = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
+ mCloseHandleUnderlapHeight = res.getDimensionPixelSize(R.dimen.close_handle_underlap);
}
/**
@@ -459,13 +462,17 @@ public class StackScrollAlgorithm {
&& !hasOngoingNotifs(algorithmState));
}
} else {
- if (view != ambientState.getTrackedHeadsUpRow()) {
+ if (view instanceof EmptyShadeView) {
+ float fullHeight = ambientState.getLayoutMaxHeight() + mCloseHandleUnderlapHeight
+ - ambientState.getStackY();
+ viewState.yTranslation = (fullHeight - getMaxAllowedChildHeight(view)) / 2f;
+ } else if (view != ambientState.getTrackedHeadsUpRow()) {
if (ambientState.isExpansionChanging()) {
// We later update shelf state, then hide views below the shelf.
viewState.hidden = false;
viewState.inShelf = algorithmState.firstViewInShelf != null
&& i >= algorithmState.visibleChildren.indexOf(
- algorithmState.firstViewInShelf);
+ algorithmState.firstViewInShelf);
} else if (ambientState.getShelf() != null) {
// When pulsing (incoming notification on AOD), innerHeight is 0; clamp all
// to shelf start, thereby hiding all notifications (except the first one, which
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index aa3b3e12b8f8..ad1c23283912 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -74,7 +74,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
private static final long BIOMETRIC_WAKELOCK_TIMEOUT_MS = 15 * 1000;
private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock:wakelock";
private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
- private static final int FP_ATTEMPTS_BEFORE_SHOW_BOUNCER = 3;
+ private static final int FP_ATTEMPTS_BEFORE_SHOW_BOUNCER = 2;
@IntDef(prefix = { "MODE_" }, value = {
MODE_NONE,
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 261b5dbac3d1..5eb35ac74732 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -3262,12 +3262,6 @@ public class NotificationPanelViewController extends PanelViewController {
mStatusBarStateController.setState(KEYGUARD);
}
return true;
- case StatusBarState.SHADE:
-
- // This gets called in the middle of the touch handling, where the state is still
- // that we are tracking the panel. Collapse the panel after this is done.
- mView.post(mPostCollapseRunnable);
- return false;
default:
return true;
}
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 2823d985102f..2bf16fc9e52c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -928,7 +928,6 @@ public abstract class PanelViewController {
private void abortAnimations() {
cancelHeightAnimator();
- mView.removeCallbacks(mPostCollapseRunnable);
mView.removeCallbacks(mFlingCollapseRunnable);
}
@@ -1105,13 +1104,6 @@ public abstract class PanelViewController {
return onMiddleClicked();
}
- protected final Runnable mPostCollapseRunnable = new Runnable() {
- @Override
- public void run() {
- collapse(false /* delayed */, 1.0f /* speedUpFactor */);
- }
- };
-
protected abstract boolean onMiddleClicked();
protected abstract boolean isDozing();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 43264b600a0e..93f9892cf5b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -45,6 +45,10 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
/**
* Base class for dialogs that should appear over panels and keyguard.
+ *
+ * Optionally provide a {@link SystemUIDialogManager} to its constructor to send signals to
+ * listeners on whether this dialog is showing.
+ *
* The SystemUIDialog registers a listener for the screen off / close system dialogs broadcast,
* and dismisses itself when it receives the broadcast.
*/
@@ -54,8 +58,9 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
"persist.systemui.flag_tablet_dialog_width";
private final Context mContext;
- private final DismissReceiver mDismissReceiver;
+ @Nullable private final DismissReceiver mDismissReceiver;
private final Handler mHandler = new Handler();
+ @Nullable private final SystemUIDialogManager mDialogManager;
private int mLastWidth = Integer.MIN_VALUE;
private int mLastHeight = Integer.MIN_VALUE;
@@ -66,11 +71,22 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
this(context, R.style.Theme_SystemUI_Dialog);
}
+ public SystemUIDialog(Context context, SystemUIDialogManager dialogManager) {
+ this(context, R.style.Theme_SystemUI_Dialog, true, dialogManager);
+ }
+
public SystemUIDialog(Context context, int theme) {
this(context, theme, true /* dismissOnDeviceLock */);
}
-
public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock) {
+ this(context, theme, dismissOnDeviceLock, null);
+ }
+
+ /**
+ * @param udfpsDialogManager If set, UDFPS will hide if this dialog is showing.
+ */
+ public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock,
+ SystemUIDialogManager dialogManager) {
super(context, theme);
mContext = context;
@@ -80,6 +96,7 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
getWindow().setAttributes(attrs);
mDismissReceiver = dismissOnDeviceLock ? new DismissReceiver(this) : null;
+ mDialogManager = dialogManager;
}
@Override
@@ -126,30 +143,7 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
* the device configuration changes, and the result will be used to resize this dialog window.
*/
protected int getWidth() {
- boolean isOnTablet =
- mContext.getResources().getConfiguration().smallestScreenWidthDp >= 600;
- if (!isOnTablet) {
- return ViewGroup.LayoutParams.MATCH_PARENT;
- }
-
- int flagValue = SystemProperties.getInt(FLAG_TABLET_DIALOG_WIDTH, 0);
- if (flagValue == -1) {
- // The width of bottom sheets (624dp).
- return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 624,
- mContext.getResources().getDisplayMetrics()));
- } else if (flagValue == -2) {
- // The suggested small width for all dialogs (348dp)
- return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 348,
- mContext.getResources().getDisplayMetrics()));
- } else if (flagValue > 0) {
- // Any given width.
- return Math.round(
- TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, flagValue,
- mContext.getResources().getDisplayMetrics()));
- } else {
- // By default we use the same width as the notification shade in portrait mode (504dp).
- return mContext.getResources().getDimensionPixelSize(R.dimen.large_dialog_width);
- }
+ return getDefaultDialogWidth(mContext);
}
/**
@@ -157,7 +151,7 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
* the device configuration changes, and the result will be used to resize this dialog window.
*/
protected int getHeight() {
- return ViewGroup.LayoutParams.WRAP_CONTENT;
+ return getDefaultDialogHeight();
}
@Override
@@ -168,6 +162,10 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
mDismissReceiver.register();
}
+ if (mDialogManager != null) {
+ mDialogManager.setShowing(this, true);
+ }
+
// Listen for configuration changes to resize this dialog window. This is mostly necessary
// for foldables that often go from large <=> small screen when folding/unfolding.
ViewRootImpl.addConfigCallback(this);
@@ -181,6 +179,10 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
mDismissReceiver.unregister();
}
+ if (mDialogManager != null) {
+ mDialogManager.setShowing(this, false);
+ }
+
ViewRootImpl.removeConfigCallback(this);
}
@@ -267,6 +269,45 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
dismissReceiver.register();
}
+ /** Set an appropriate size to {@code dialog} depending on the current configuration. */
+ public static void setDialogSize(Dialog dialog) {
+ // We need to create the dialog first, otherwise the size will be overridden when it is
+ // created.
+ dialog.create();
+ dialog.getWindow().setLayout(getDefaultDialogWidth(dialog.getContext()),
+ getDefaultDialogHeight());
+ }
+
+ private static int getDefaultDialogWidth(Context context) {
+ boolean isOnTablet = context.getResources().getConfiguration().smallestScreenWidthDp >= 600;
+ if (!isOnTablet) {
+ return ViewGroup.LayoutParams.MATCH_PARENT;
+ }
+
+ int flagValue = SystemProperties.getInt(FLAG_TABLET_DIALOG_WIDTH, 0);
+ if (flagValue == -1) {
+ // The width of bottom sheets (624dp).
+ return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 624,
+ context.getResources().getDisplayMetrics()));
+ } else if (flagValue == -2) {
+ // The suggested small width for all dialogs (348dp)
+ return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 348,
+ context.getResources().getDisplayMetrics()));
+ } else if (flagValue > 0) {
+ // Any given width.
+ return Math.round(
+ TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, flagValue,
+ context.getResources().getDisplayMetrics()));
+ } else {
+ // By default we use the same width as the notification shade in portrait mode (504dp).
+ return context.getResources().getDimensionPixelSize(R.dimen.large_dialog_width);
+ }
+ }
+
+ private static int getDefaultDialogHeight() {
+ return ViewGroup.LayoutParams.WRAP_CONTENT;
+ }
+
private static class DismissReceiver extends BroadcastReceiver {
private static final IntentFilter INTENT_FILTER = new IntentFilter();
static {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogManager.java
new file mode 100644
index 000000000000..204f710b633a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogManager.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2021 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 androidx.annotation.NonNull;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dump.DumpManager;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+/**
+ * Register dialogs to this manager if extraneous affordances (like the UDFPS sensor area)
+ * should be hidden from the screen when the dialog shows.
+ *
+ * Currently, only used if UDFPS is supported on the device; however, can be extended in the future
+ * for other use cases.
+ */
+@SysUISingleton
+public class SystemUIDialogManager implements Dumpable {
+ private final StatusBarKeyguardViewManager mKeyguardViewManager;
+
+ private final Set<SystemUIDialog> mDialogsShowing = new HashSet<>();
+ private final Set<Listener> mListeners = new HashSet<>();
+
+ @Inject
+ public SystemUIDialogManager(
+ DumpManager dumpManager,
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+ dumpManager.registerDumpable(this);
+ mKeyguardViewManager = statusBarKeyguardViewManager;
+ }
+
+ /**
+ * Whether listeners should hide affordances like the UDFPS sensor icon.
+ */
+ public boolean shouldHideAffordance() {
+ return !mDialogsShowing.isEmpty();
+ }
+
+ /**
+ * Register a listener to receive callbacks.
+ */
+ public void registerListener(@NonNull Listener listener) {
+ mListeners.add(listener);
+ }
+
+ /**
+ * Unregister a listener from receiving callbacks.
+ */
+ public void unregisterListener(@NonNull Listener listener) {
+ mListeners.remove(listener);
+ }
+
+ void setShowing(SystemUIDialog dialog, boolean showing) {
+ final boolean wasHidingAffordances = shouldHideAffordance();
+ if (showing) {
+ mDialogsShowing.add(dialog);
+ } else {
+ mDialogsShowing.remove(dialog);
+ }
+
+ if (wasHidingAffordances != shouldHideAffordance()) {
+ updateDialogListeners();
+ }
+ }
+
+ private void updateDialogListeners() {
+ if (shouldHideAffordance()) {
+ mKeyguardViewManager.resetAlternateAuth(true);
+ }
+
+ for (Listener listener : mListeners) {
+ listener.shouldHideAffordances(shouldHideAffordance());
+ }
+ }
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("listeners:");
+ for (Listener listener : mListeners) {
+ pw.println("\t" + listener);
+ }
+ pw.println("dialogs tracked:");
+ for (SystemUIDialog dialog : mDialogsShowing) {
+ pw.println("\t" + dialog);
+ }
+ }
+
+ /** SystemUIDialogManagerListener */
+ public interface Listener {
+ /**
+ * Callback where shouldHide=true if listeners should hide their views that may overlap
+ * a showing dialog.
+ */
+ void shouldHideAffordances(boolean shouldHide);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 36e56f967424..ebf5a6da5d1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -1161,7 +1161,7 @@ public class UserSwitcherController implements Dumpable {
? com.android.settingslib.R.string.guest_reset_guest_dialog_title
: R.string.guest_exit_guest_dialog_title);
setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
- setButton(DialogInterface.BUTTON_NEGATIVE,
+ setButton(DialogInterface.BUTTON_NEUTRAL,
context.getString(android.R.string.cancel), this);
setButton(DialogInterface.BUTTON_POSITIVE,
context.getString(mGuestUserAutoCreated
@@ -1180,7 +1180,7 @@ public class UserSwitcherController implements Dumpable {
if (mFalsingManager.isFalseTap(penalty)) {
return;
}
- if (which == BUTTON_NEGATIVE) {
+ if (which == BUTTON_NEUTRAL) {
cancel();
} else {
mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE);
@@ -1198,7 +1198,7 @@ public class UserSwitcherController implements Dumpable {
super(context);
setTitle(R.string.user_add_user_title);
setMessage(context.getString(R.string.user_add_user_message_short));
- setButton(DialogInterface.BUTTON_NEGATIVE,
+ setButton(DialogInterface.BUTTON_NEUTRAL,
context.getString(android.R.string.cancel), this);
setButton(DialogInterface.BUTTON_POSITIVE,
context.getString(android.R.string.ok), this);
@@ -1212,7 +1212,7 @@ public class UserSwitcherController implements Dumpable {
if (mFalsingManager.isFalseTap(penalty)) {
return;
}
- if (which == BUTTON_NEGATIVE) {
+ if (which == BUTTON_NEUTRAL) {
cancel();
} else {
mDialogLaunchAnimator.dismissStack(this);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index b546edf428b8..1fd47a465623 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -56,6 +56,7 @@ import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tracing.nano.SystemUiTraceProto;
import com.android.wm.shell.ShellCommandHandler;
+import com.android.wm.shell.compatui.CompatUI;
import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
@@ -66,7 +67,6 @@ import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
import com.android.wm.shell.onehanded.OneHandedUiEventLogger;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.protolog.ShellProtoLogImpl;
-import com.android.wm.shell.sizecompatui.SizeCompatUI;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.FileDescriptor;
@@ -114,7 +114,7 @@ public final class WMShell extends SystemUI
private final Optional<OneHanded> mOneHandedOptional;
private final Optional<HideDisplayCutout> mHideDisplayCutoutOptional;
private final Optional<ShellCommandHandler> mShellCommandHandler;
- private final Optional<SizeCompatUI> mSizeCompatUIOptional;
+ private final Optional<CompatUI> mCompatUIOptional;
private final Optional<DragAndDrop> mDragAndDropOptional;
private final CommandQueue mCommandQueue;
@@ -132,7 +132,7 @@ public final class WMShell extends SystemUI
private KeyguardUpdateMonitorCallback mSplitScreenKeyguardCallback;
private KeyguardUpdateMonitorCallback mPipKeyguardCallback;
private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback;
- private KeyguardUpdateMonitorCallback mSizeCompatUIKeyguardCallback;
+ private KeyguardUpdateMonitorCallback mCompatUIKeyguardCallback;
private WakefulnessLifecycle.Observer mWakefulnessObserver;
@Inject
@@ -143,7 +143,7 @@ public final class WMShell extends SystemUI
Optional<OneHanded> oneHandedOptional,
Optional<HideDisplayCutout> hideDisplayCutoutOptional,
Optional<ShellCommandHandler> shellCommandHandler,
- Optional<SizeCompatUI> sizeCompatUIOptional,
+ Optional<CompatUI> sizeCompatUIOptional,
Optional<DragAndDrop> dragAndDropOptional,
CommandQueue commandQueue,
ConfigurationController configurationController,
@@ -169,7 +169,7 @@ public final class WMShell extends SystemUI
mWakefulnessLifecycle = wakefulnessLifecycle;
mProtoTracer = protoTracer;
mShellCommandHandler = shellCommandHandler;
- mSizeCompatUIOptional = sizeCompatUIOptional;
+ mCompatUIOptional = sizeCompatUIOptional;
mDragAndDropOptional = dragAndDropOptional;
mSysUiMainExecutor = sysUiMainExecutor;
}
@@ -185,7 +185,7 @@ public final class WMShell extends SystemUI
mSplitScreenOptional.ifPresent(this::initSplitScreen);
mOneHandedOptional.ifPresent(this::initOneHanded);
mHideDisplayCutoutOptional.ifPresent(this::initHideDisplayCutout);
- mSizeCompatUIOptional.ifPresent(this::initSizeCompatUi);
+ mCompatUIOptional.ifPresent(this::initCompatUi);
mDragAndDropOptional.ifPresent(this::initDragAndDrop);
}
@@ -391,14 +391,14 @@ public final class WMShell extends SystemUI
}
@VisibleForTesting
- void initSizeCompatUi(SizeCompatUI sizeCompatUI) {
- mSizeCompatUIKeyguardCallback = new KeyguardUpdateMonitorCallback() {
+ void initCompatUi(CompatUI sizeCompatUI) {
+ mCompatUIKeyguardCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onKeyguardOccludedChanged(boolean occluded) {
sizeCompatUI.onKeyguardOccludedChanged(occluded);
}
};
- mKeyguardUpdateMonitor.registerCallback(mSizeCompatUIKeyguardCallback);
+ mKeyguardUpdateMonitor.registerCallback(mCompatUIKeyguardCallback);
}
void initDragAndDrop(DragAndDrop dragAndDrop) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 9e42ff37ea69..ac221a9f7891 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -65,6 +65,7 @@ import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -170,6 +171,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
private TypedArray mBrightnessValues;
@Mock
private TypedArray mBrightnessBacklight;
+ @Mock
+ private SystemUIDialogManager mSystemUIDialogManager;
// Capture listeners so that they can be used to send events
@Captor private ArgumentCaptor<IUdfpsOverlayController> mOverlayCaptor;
@@ -179,8 +182,6 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Captor private ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor;
private ScreenLifecycle.Observer mScreenObserver;
- @Captor private ArgumentCaptor<UdfpsAnimationViewController> mAnimViewControllerCaptor;
-
@Before
public void setUp() {
setUpResources();
@@ -238,7 +239,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
mHandler,
mConfigurationController,
mSystemClock,
- mUnlockedScreenOffAnimationController);
+ mUnlockedScreenOffAnimationController,
+ mSystemUIDialogManager);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -642,12 +644,12 @@ public class UdfpsControllerTest extends SysuiTestCase {
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
moveEvent.recycle();
- // THEN low-tick haptic is played
+ // THEN click haptic is played
verify(mVibrator).vibrate(
anyInt(),
anyString(),
any(),
- eq("udfps-onStart-tick"),
+ eq("udfps-onStart-click"),
eq(UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES));
// THEN make sure vibration attributes has so that it always will play the haptic,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 1cf21ac40e31..0ae3c39e659b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -42,6 +42,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
@@ -92,6 +93,8 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
@Mock
private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@Mock
+ private SystemUIDialogManager mDialogManager;
+ @Mock
private UdfpsController mUdfpsController;
private FakeSystemClock mSystemClock = new FakeSystemClock();
@@ -130,6 +133,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
mSystemClock,
mKeyguardStateController,
mUnlockedScreenOffAnimationController,
+ mDialogManager,
mUdfpsController);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
new file mode 100644
index 000000000000..87b9172dcefc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 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.controls.ui
+
+import android.app.PendingIntent
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.wm.shell.TaskView
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class DetailDialogTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var taskView: TaskView
+ @Mock
+ private lateinit var controlViewHolder: ControlViewHolder
+ @Mock
+ private lateinit var pendingIntent: PendingIntent
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun testPendingIntentIsUnModified() {
+ // GIVEN the dialog is created with a PendingIntent
+ val dialog = createDialog(pendingIntent)
+
+ // WHEN the TaskView is initialized
+ dialog.stateCallback.onInitialized()
+
+ // THEN the PendingIntent used to call startActivity is unmodified by systemui
+ verify(taskView).startActivity(eq(pendingIntent), any(), any(), any())
+ }
+
+ private fun createDialog(pendingIntent: PendingIntent): DetailDialog {
+ return DetailDialog(
+ mContext,
+ taskView,
+ pendingIntent,
+ controlViewHolder
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index bf5522c50a78..e3a7e3b43b77 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -62,6 +62,7 @@ import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.telephony.TelephonyListenerManager;
@@ -117,6 +118,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
@Mock private StatusBar mStatusBar;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private DialogLaunchAnimator mDialogLaunchAnimator;
+ @Mock private SystemUIDialogManager mDialogManager;
private TestableLooper mTestableLooper;
@@ -162,7 +164,8 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase {
mPackageManager,
Optional.of(mStatusBar),
mKeyguardUpdateMonitor,
- mDialogLaunchAnimator);
+ mDialogLaunchAnimator,
+ mDialogManager);
mGlobalActionsDialogLite.setZeroDialogPressDelayForTesting();
ColorExtractor.GradientColors backdropColors = new ColorExtractor.GradientColors();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
index 81bcbfb1f460..d7c00fbe1e85 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -26,7 +26,6 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -43,7 +42,6 @@ import android.os.Vibrator;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Pair;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
@@ -69,8 +67,6 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
-import com.airbnb.lottie.LottieAnimationView;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -110,8 +106,6 @@ public class LockIconViewControllerTest extends SysuiTestCase {
private @Mock ConfigurationController mConfigurationController;
private @Mock Vibrator mVibrator;
private @Mock AuthRippleController mAuthRippleController;
- private @Mock LottieAnimationView mAodFp;
- private @Mock LayoutInflater mLayoutInflater;
private FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock());
private LockIconViewController mLockIconViewController;
@@ -149,7 +143,6 @@ public class LockIconViewControllerTest extends SysuiTestCase {
when(mLockIconView.getResources()).thenReturn(mResources);
when(mLockIconView.getContext()).thenReturn(mContext);
- when(mLockIconView.findViewById(R.layout.udfps_aod_lock_icon)).thenReturn(mAodFp);
when(mContext.getResources()).thenReturn(mResources);
when(mContext.getSystemService(WindowManager.class)).thenReturn(mWindowManager);
Rect windowBounds = new Rect(0, 0, 800, 1200);
@@ -176,8 +169,7 @@ public class LockIconViewControllerTest extends SysuiTestCase {
mDelayableExecutor,
mVibrator,
mAuthRippleController,
- mResources,
- mLayoutInflater
+ mResources
);
}
@@ -187,35 +179,6 @@ public class LockIconViewControllerTest extends SysuiTestCase {
}
@Test
- public void testIgnoreUdfpsWhenNotSupported() {
- // GIVEN Udpfs sensor is NOT available
- mLockIconViewController.init();
- captureAttachListener();
-
- // WHEN the view is attached
- mAttachListener.onViewAttachedToWindow(mLockIconView);
-
- // THEN lottie animation should NOT be inflated
- verify(mLayoutInflater, never()).inflate(eq(R.layout.udfps_aod_lock_icon), any());
- }
-
- @Test
- public void testInflateUdfpsWhenSupported() {
- // GIVEN Udpfs sensor is available
- setupUdfps();
- when(mKeyguardUpdateMonitor.isUdfpsEnrolled()).thenReturn(true);
-
- mLockIconViewController.init();
- captureAttachListener();
-
- // WHEN the view is attached
- mAttachListener.onViewAttachedToWindow(mLockIconView);
-
- // THEN lottie animation should be inflated
- verify(mLayoutInflater).inflate(eq(R.layout.udfps_aod_lock_icon), any());
- }
-
- @Test
public void testUpdateFingerprintLocationOnInit() {
// GIVEN fp sensor location is available pre-attached
Pair<Integer, PointF> udfps = setupUdfps();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 053851ec385d..451291d264b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -43,6 +43,7 @@ import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.Before;
import org.junit.Test;
@@ -65,6 +66,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
+ private final SystemUIDialogManager mDialogManager = mock(SystemUIDialogManager.class);
private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl;
private MediaOutputController mMediaOutputController;
@@ -77,7 +79,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext,
mMediaOutputController);
mMediaOutputBaseDialogImpl.onCreate(new Bundle());
@@ -167,7 +169,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
class MediaOutputBaseDialogImpl extends MediaOutputBaseDialog {
MediaOutputBaseDialogImpl(Context context, MediaOutputController mediaOutputController) {
- super(context, mediaOutputController);
+ super(context, mediaOutputController, mDialogManager);
mAdapter = mMediaOutputBaseAdapter;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index 09ec4ca0e1df..cd26e0d960dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -54,6 +54,7 @@ import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.Before;
import org.junit.Test;
@@ -93,6 +94,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
+ private final SystemUIDialogManager mDialogManager = mock(SystemUIDialogManager.class);
private Context mSpyContext;
private MediaOutputController mMediaOutputController;
@@ -115,7 +117,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
MediaDescription.Builder builder = new MediaDescription.Builder();
@@ -159,7 +161,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
public void start_withoutPackageName_verifyMediaControllerInit() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
mMediaOutputController.start(mCb);
@@ -180,7 +182,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
public void stop_withoutPackageName_verifyMediaControllerDeinit() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
mMediaOutputController.start(mCb);
@@ -451,7 +453,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
public void getNotificationLargeIcon_withoutPackageName_returnsNull() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
assertThat(mMediaOutputController.getNotificationIcon()).isNull();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index 8a3ea562269d..ada8d3592012 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -40,6 +40,7 @@ import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.After;
import org.junit.Before;
@@ -67,6 +68,7 @@ public class MediaOutputDialogTest extends SysuiTestCase {
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
+ private final SystemUIDialogManager mDialogManager = mock(SystemUIDialogManager.class);
private MediaOutputDialog mMediaOutputDialog;
private MediaOutputController mMediaOutputController;
@@ -76,10 +78,10 @@ public class MediaOutputDialogTest extends SysuiTestCase {
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
mMediaOutputDialog = new MediaOutputDialog(mContext, false,
- mMediaOutputController, mUiEventLogger);
+ mMediaOutputController, mUiEventLogger, mDialogManager);
mMediaOutputDialog.show();
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice);
@@ -125,7 +127,7 @@ public class MediaOutputDialogTest extends SysuiTestCase {
// and verify if the calling times increases.
public void onCreate_ShouldLogVisibility() {
MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false,
- mMediaOutputController, mUiEventLogger);
+ mMediaOutputController, mUiEventLogger, mDialogManager);
testDialog.show();
testDialog.dismissDialog();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
index e8cd6c88956d..b114452facc3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
@@ -38,6 +38,7 @@ import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.After;
import org.junit.Before;
@@ -66,6 +67,7 @@ public class MediaOutputGroupDialogTest extends SysuiTestCase {
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
+ private final SystemUIDialogManager mDialogManager = mock(SystemUIDialogManager.class);
private MediaOutputGroupDialog mMediaOutputGroupDialog;
private MediaOutputController mMediaOutputController;
@@ -75,10 +77,10 @@ public class MediaOutputGroupDialogTest extends SysuiTestCase {
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
mMediaOutputGroupDialog = new MediaOutputGroupDialog(mContext, false,
- mMediaOutputController);
+ mMediaOutputController, mDialogManager);
mMediaOutputGroupDialog.show();
when(mLocalMediaManager.getSelectedMediaDevice()).thenReturn(mMediaDevices);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index 6dca2a73b57b..47f6e5c420f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -235,10 +235,18 @@ public class InternetDialogControllerTest extends SysuiTestCase {
}
@Test
- public void getSubtitleText_withAirplaneModeOn_returnNull() {
+ public void getSubtitleText_withApmOnAndWifiOff_returnWifiIsOff() {
fakeAirplaneModeEnabled(true);
+ when(mWifiManager.isWifiEnabled()).thenReturn(false);
- assertThat(mInternetDialogController.getSubtitleText(false)).isNull();
+ assertThat(mInternetDialogController.getSubtitleText(false))
+ .isEqualTo(getResourcesString("wifi_is_off"));
+
+ // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+ mInternetDialogController.mCanConfigWifi = false;
+
+ assertThat(mInternetDialogController.getSubtitleText(false))
+ .isNotEqualTo(getResourcesString("wifi_is_off"));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index 651bcdef9978..89537884903a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -140,7 +140,7 @@ public class InternetDialogTest extends SysuiTestCase {
mInternetDialog.updateDialog(true);
- assertThat(mSubTitle.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index 5b60c9e07342..ea681435132e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -4,6 +4,7 @@ import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.EmptyShadeView
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider
@@ -55,4 +56,24 @@ class StackScrollAlgorithmTest : SysuiTestCase() {
// top margin presence should decrease heads up translation up to minHeadsUpTranslation
assertThat(expandableViewState.yTranslation).isEqualTo(minHeadsUpTranslation)
}
-} \ No newline at end of file
+
+ @Test
+ fun resetViewStates_childIsEmptyShadeView_viewIsCenteredVertically() {
+ stackScrollAlgorithm.initView(context)
+ val emptyShadeView = EmptyShadeView(context, /* attrs= */ null).apply {
+ layout(/* l= */ 0, /* t= */ 0, /* r= */ 100, /* b= */ 100)
+ }
+ hostView.removeAllViews()
+ hostView.addView(emptyShadeView)
+ ambientState.layoutMaxHeight = 1280
+
+ stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+ val closeHandleUnderlapHeight =
+ context.resources.getDimensionPixelSize(R.dimen.close_handle_underlap)
+ val fullHeight =
+ ambientState.layoutMaxHeight + closeHandleUnderlapHeight - ambientState.stackY
+ val centeredY = ambientState.stackY + fullHeight / 2f - emptyShadeView.height / 2f
+ assertThat(emptyShadeView.viewState?.yTranslation).isEqualTo(centeredY)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 07debe68e224..c3349f1d70f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -381,16 +381,15 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
}
@Test
- public void onUdfpsConsecutivelyFailedThreeTimes_showBouncer() {
+ public void onUdfpsConsecutivelyFailedTwoTimes_showBouncer() {
// GIVEN UDFPS is supported
when(mUpdateMonitor.isUdfpsSupported()).thenReturn(true);
- // WHEN udfps fails twice - then don't show the bouncer
- mBiometricUnlockController.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT);
+ // WHEN udfps fails once - then don't show the bouncer
mBiometricUnlockController.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT);
verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
- // WHEN udfps fails the third time
+ // WHEN udfps fails the second time
mBiometricUnlockController.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT);
// THEN show the bouncer
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 1e15d2ae0bdb..2f2e536322db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -35,6 +35,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.compatui.CompatUI;
import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
@@ -42,7 +43,6 @@ import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedEventCallback;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.sizecompatui.SizeCompatUI;
import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.Before;
@@ -78,7 +78,7 @@ public class WMShellTest extends SysuiTestCase {
@Mock WakefulnessLifecycle mWakefulnessLifecycle;
@Mock ProtoTracer mProtoTracer;
@Mock ShellCommandHandler mShellCommandHandler;
- @Mock SizeCompatUI mSizeCompatUI;
+ @Mock CompatUI mCompatUI;
@Mock ShellExecutor mSysUiMainExecutor;
@Mock DragAndDrop mDragAndDrop;
@@ -88,7 +88,7 @@ public class WMShellTest extends SysuiTestCase {
mWMShell = new WMShell(mContext, Optional.of(mPip), Optional.of(mLegacySplitScreen),
Optional.of(mSplitScreen), Optional.of(mOneHanded), Optional.of(mHideDisplayCutout),
- Optional.of(mShellCommandHandler), Optional.of(mSizeCompatUI),
+ Optional.of(mShellCommandHandler), Optional.of(mCompatUI),
Optional.of(mDragAndDrop),
mCommandQueue, mConfigurationController, mKeyguardUpdateMonitor,
mNavigationModeController, mScreenLifecycle, mSysUiState, mProtoTracer,
@@ -136,8 +136,8 @@ public class WMShellTest extends SysuiTestCase {
}
@Test
- public void initSizeCompatUI_registersCallbacks() {
- mWMShell.initSizeCompatUi(mSizeCompatUI);
+ public void initCompatUI_registersCallbacks() {
+ mWMShell.initCompatUi(mCompatUI);
verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
}
diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
index eaf269415fdc..6744ea8e26a5 100644
--- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
@@ -288,8 +288,6 @@ public class SystemActionPerformer {
showGlobalActions();
return true;
}
- case AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN:
- return toggleSplitScreen();
case AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN:
return lockScreen();
case AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT:
@@ -369,21 +367,6 @@ public class SystemActionPerformer {
mWindowManagerService.showGlobalActions();
}
- private boolean toggleSplitScreen() {
- final long token = Binder.clearCallingIdentity();
- try {
- StatusBarManagerInternal statusBarService = LocalServices.getService(
- StatusBarManagerInternal.class);
- if (statusBarService == null) {
- return false;
- }
- statusBarService.toggleSplitScreen();
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- return true;
- }
-
private boolean lockScreen() {
mContext.getSystemService(PowerManager.class).goToSleep(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_ACCESSIBILITY, 0);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 53b1608841b4..ec15af335c78 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4184,7 +4184,7 @@ public class ActivityManagerService extends IActivityManager.Stub
didSomething |= mProcessList.killPackageProcessesLSP(packageName, appId, userId,
ProcessList.INVALID_ADJ, callerWillRestart, false /* allowRestart */, doit,
- evenPersistent, true /* setRemoved */,
+ evenPersistent, true /* setRemoved */, uninstalling,
packageName == null ? ApplicationExitInfo.REASON_USER_STOPPED
: ApplicationExitInfo.REASON_USER_REQUESTED,
ApplicationExitInfo.SUBREASON_UNKNOWN,
@@ -7220,6 +7220,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ProcessList.PERSISTENT_PROC_ADJ, false /* callerWillRestart */,
true /* callerWillRestart */, true /* doit */,
true /* evenPersistent */, false /* setRemoved */,
+ false /* uninstalling */,
ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_KILL_UID,
reason != null ? reason : "kill uid");
@@ -7241,6 +7242,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ProcessList.PERSISTENT_PROC_ADJ, false /* callerWillRestart */,
true /* callerWillRestart */, true /* doit */,
true /* evenPersistent */, false /* setRemoved */,
+ false /* uninstalling */,
ApplicationExitInfo.REASON_PERMISSION_CHANGE,
ApplicationExitInfo.SUBREASON_UNKNOWN,
reason != null ? reason : "kill uid");
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index ff480d1f614c..7673123c6476 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1633,7 +1633,7 @@ public class OomAdjuster {
int schedGroup;
int procState;
int cachedAdjSeq;
- int capability = 0;
+ int capability = cycleReEval ? app.mState.getCurCapability() : 0;
boolean foregroundActivities = false;
boolean hasVisibleActivities = false;
@@ -2018,10 +2018,6 @@ public class OomAdjuster {
}
if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) {
- if (shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) {
- continue;
- }
-
if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
capability |= cstate.getCurCapability();
}
@@ -2042,6 +2038,10 @@ public class OomAdjuster {
}
}
+ if (shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) {
+ continue;
+ }
+
if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
// we are going to consider it empty. The specific cached state
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index b77270f5963b..1e66ed42ff96 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -374,6 +374,16 @@ public final class ProcessList {
private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
/**
+ * Native heap allocations in AppZygote process and its descendants will now have a
+ * non-zero tag in the most significant byte.
+ * @see <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
+ * Pointers</a>
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
+ private static final long NATIVE_HEAP_POINTER_TAGGING_APP_ZYGOTE = 207557677;
+
+ /**
* Enable asynchronous (ASYNC) memory tag checking in this process. This
* flag will only have an effect on hardware supporting the ARM Memory
* Tagging Extension (MTE).
@@ -1738,6 +1748,16 @@ public final class ProcessList {
return level;
}
+ private int decideTaggingLevelForAppZygote(ProcessRecord app) {
+ int level = decideTaggingLevel(app);
+ // TBI ("fake" pointer tagging) in AppZygote is controlled by a separate compat feature.
+ if (!mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING_APP_ZYGOTE, app.info)
+ && level == Zygote.MEMORY_TAG_LEVEL_TBI) {
+ level = Zygote.MEMORY_TAG_LEVEL_NONE;
+ }
+ return level;
+ }
+
private int decideGwpAsanLevel(ProcessRecord app) {
// Look at the process attribute first.
if (app.processInfo != null
@@ -2238,7 +2258,8 @@ public final class ProcessList {
// not the calling one.
appInfo.packageName = app.getHostingRecord().getDefiningPackageName();
appInfo.uid = uid;
- appZygote = new AppZygote(appInfo, uid, firstUid, lastUid);
+ int runtimeFlags = decideTaggingLevelForAppZygote(app);
+ appZygote = new AppZygote(appInfo, uid, firstUid, lastUid, runtimeFlags);
mAppZygotes.put(app.info.processName, uid, appZygote);
zygoteProcessList = new ArrayList<ProcessRecord>();
mAppZygoteProcesses.put(appZygote, zygoteProcessList);
@@ -2750,8 +2771,8 @@ public final class ProcessList {
int reasonCode, int subReason, String reason) {
return killPackageProcessesLSP(packageName, appId, userId, minOomAdj,
false /* callerWillRestart */, true /* allowRestart */, true /* doit */,
- false /* evenPersistent */, false /* setRemoved */, reasonCode,
- subReason, reason);
+ false /* evenPersistent */, false /* setRemoved */, false /* uninstalling */,
+ reasonCode, subReason, reason);
}
@GuardedBy("mService")
@@ -2784,9 +2805,10 @@ public final class ProcessList {
@GuardedBy({"mService", "mProcLock"})
boolean killPackageProcessesLSP(String packageName, int appId,
int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
- boolean doit, boolean evenPersistent, boolean setRemoved, int reasonCode,
- int subReason, String reason) {
- ArrayList<ProcessRecord> procs = new ArrayList<>();
+ boolean doit, boolean evenPersistent, boolean setRemoved, boolean uninstalling,
+ int reasonCode, int subReason, String reason) {
+ final PackageManagerInternal pm = mService.getPackageManagerInternal();
+ final ArrayList<Pair<ProcessRecord, Boolean>> procs = new ArrayList<>();
// Remove all processes this package may have touched: all with the
// same UID (except for the system or root user), and all whose name
@@ -2803,7 +2825,18 @@ public final class ProcessList {
}
if (app.isRemoved()) {
if (doit) {
- procs.add(app);
+ boolean shouldAllowRestart = false;
+ if (!uninstalling && packageName != null) {
+ // This package has a dependency on the given package being stopped,
+ // while it's not being frozen nor uninstalled, allow to restart it.
+ shouldAllowRestart = !app.getPkgList().containsKey(packageName)
+ && app.getPkgDeps() != null
+ && app.getPkgDeps().contains(packageName)
+ && app.info != null
+ && !pm.isPackageFrozen(app.info.packageName, app.uid,
+ app.userId);
+ }
+ procs.add(new Pair<>(app, shouldAllowRestart));
}
continue;
}
@@ -2818,6 +2851,8 @@ public final class ProcessList {
continue;
}
+ boolean shouldAllowRestart = false;
+
// If no package is specified, we call all processes under the
// give user id.
if (packageName == null) {
@@ -2839,9 +2874,16 @@ public final class ProcessList {
if (userId != UserHandle.USER_ALL && app.userId != userId) {
continue;
}
- if (!app.getPkgList().containsKey(packageName) && !isDep) {
+ final boolean isInPkgList = app.getPkgList().containsKey(packageName);
+ if (!isInPkgList && !isDep) {
continue;
}
+ if (!isInPkgList && isDep && !uninstalling && app.info != null
+ && !pm.isPackageFrozen(app.info.packageName, app.uid, app.userId)) {
+ // This package has a dependency on the given package being stopped,
+ // while it's not being frozen nor uninstalled, allow to restart it.
+ shouldAllowRestart = true;
+ }
}
// Process has passed all conditions, kill it!
@@ -2851,14 +2893,15 @@ public final class ProcessList {
if (setRemoved) {
app.setRemoved(true);
}
- procs.add(app);
+ procs.add(new Pair<>(app, shouldAllowRestart));
}
}
int N = procs.size();
for (int i=0; i<N; i++) {
- removeProcessLocked(procs.get(i), callerWillRestart, allowRestart,
- reasonCode, subReason, reason);
+ final Pair<ProcessRecord, Boolean> proc = procs.get(i);
+ removeProcessLocked(proc.first, callerWillRestart, allowRestart || proc.second,
+ reasonCode, subReason, reason);
}
killAppZygotesLocked(packageName, appId, userId, false /* force */);
mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 5ecdfe49cdf7..f053e942fe6b 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -328,7 +328,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
boolean isBtScoRequested = isBluetoothScoRequested();
- if (isBtScoRequested && !wasBtScoRequested) {
+ if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive())) {
if (!mBtHelper.startBluetoothSco(scoAudioMode, eventSource)) {
Log.w(TAG, "setCommunicationRouteForClient: failure to start BT SCO for pid: "
+ pid);
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 7341e744dea3..358263df916b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -503,10 +503,14 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
protected int getShowOverlayReason() {
if (isKeyguard()) {
return BiometricOverlayConstants.REASON_AUTH_KEYGUARD;
- } else if (isSettings()) {
- return BiometricOverlayConstants.REASON_AUTH_SETTINGS;
} else if (isBiometricPrompt()) {
+ // BP reason always takes precedent over settings, since callers from within
+ // settings can always invoke BP.
return BiometricOverlayConstants.REASON_AUTH_BP;
+ } else if (isSettings()) {
+ // This is pretty much only for FingerprintManager#authenticate usage from
+ // FingerprintSettings.
+ return BiometricOverlayConstants.REASON_AUTH_SETTINGS;
} else {
return BiometricOverlayConstants.REASON_AUTH_OTHER;
}
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 5ce72c2fd080..3120dc58eebd 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -25,7 +25,6 @@ import android.annotation.TestApi;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.compat.CompatChanges;
-import android.app.TaskStackListener;
import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
import android.compat.annotation.Overridable;
@@ -35,6 +34,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
import android.hardware.CameraSessionStats;
import android.hardware.CameraStreamStats;
@@ -84,7 +84,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -309,8 +308,6 @@ public class CameraServiceProxy extends SystemService
private final DisplayWindowListener mDisplayWindowListener = new DisplayWindowListener();
- private final TaskStateHandler mTaskStackListener = new TaskStateHandler();
-
public static final class TaskInfo {
public int frontTaskId;
public boolean isResizeable;
@@ -320,54 +317,6 @@ public class CameraServiceProxy extends SystemService
public int userId;
}
- private final class TaskStateHandler extends TaskStackListener {
- private final Object mMapLock = new Object();
-
- // maps the package name to its corresponding current top level task id
- @GuardedBy("mMapLock")
- private final ArrayMap<String, TaskInfo> mTaskInfoMap = new ArrayMap<>();
-
- @Override
- public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
- synchronized (mMapLock) {
- TaskInfo info = new TaskInfo();
- info.frontTaskId = taskInfo.taskId;
- info.isResizeable =
- (taskInfo.topActivityInfo.resizeMode != RESIZE_MODE_UNRESIZEABLE);
- info.displayId = taskInfo.displayId;
- info.userId = taskInfo.userId;
- info.isFixedOrientationLandscape = ActivityInfo.isFixedOrientationLandscape(
- taskInfo.topActivityInfo.screenOrientation);
- info.isFixedOrientationPortrait = ActivityInfo.isFixedOrientationPortrait(
- taskInfo.topActivityInfo.screenOrientation);
- mTaskInfoMap.put(taskInfo.topActivityInfo.packageName, info);
- }
- }
-
- @Override
- public void onTaskRemoved(int taskId) {
- synchronized (mMapLock) {
- for (Map.Entry<String, TaskInfo> entry : mTaskInfoMap.entrySet()){
- if (entry.getValue().frontTaskId == taskId) {
- mTaskInfoMap.remove(entry.getKey());
- break;
- }
- }
- }
- }
-
- public @Nullable TaskInfo getFrontTaskInfo(String packageName) {
- synchronized (mMapLock) {
- if (mTaskInfoMap.containsKey(packageName)) {
- return mTaskInfoMap.get(packageName);
- }
- }
-
- Log.e(TAG, "Top task with package name: " + packageName + " not found!");
- return null;
- }
- }
-
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -490,18 +439,53 @@ public class CameraServiceProxy extends SystemService
private final ICameraServiceProxy.Stub mCameraServiceProxy = new ICameraServiceProxy.Stub() {
@Override
- public int getRotateAndCropOverride(String packageName, int lensFacing) {
+ public int getRotateAndCropOverride(String packageName, int lensFacing, int userId) {
if (Binder.getCallingUid() != Process.CAMERASERVER_UID) {
Slog.e(TAG, "Calling UID: " + Binder.getCallingUid() + " doesn't match expected " +
" camera service UID!");
return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE;
}
+ TaskInfo taskInfo = null;
+ ParceledListSlice<ActivityManager.RecentTaskInfo> recentTasks = null;
+
+ try {
+ recentTasks = ActivityTaskManager.getService().getRecentTasks(/*maxNum*/1,
+ /*flags*/ 0, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to query recent tasks!");
+ return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE;
+ }
+
+ if ((recentTasks != null) && (!recentTasks.getList().isEmpty())) {
+ ActivityManager.RecentTaskInfo task = recentTasks.getList().get(0);
+ if (packageName.equals(task.topActivityInfo.packageName)) {
+ taskInfo = new TaskInfo();
+ taskInfo.frontTaskId = task.taskId;
+ taskInfo.isResizeable =
+ (task.topActivityInfo.resizeMode != RESIZE_MODE_UNRESIZEABLE);
+ taskInfo.displayId = task.displayId;
+ taskInfo.userId = task.userId;
+ taskInfo.isFixedOrientationLandscape =
+ ActivityInfo.isFixedOrientationLandscape(
+ task.topActivityInfo.screenOrientation);
+ taskInfo.isFixedOrientationPortrait =
+ ActivityInfo.isFixedOrientationPortrait(
+ task.topActivityInfo.screenOrientation);
+ } else {
+ Log.e(TAG, "Recent task package name: " + task.topActivityInfo.packageName
+ + " doesn't match with camera client package name: " + packageName);
+ return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE;
+ }
+ } else {
+ Log.e(TAG, "Recent task list is empty!");
+ return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE;
+ }
+
// TODO: Modify the sensor orientation in camera characteristics along with any 3A
// regions in capture requests/results to account for thea physical rotation. The
// former is somewhat tricky as it assumes that camera clients always check for the
// current value by retrieving the camera characteristics from the camera device.
- TaskInfo taskInfo = mTaskStackListener.getFrontTaskInfo(packageName);
if ((taskInfo != null) && (CompatChanges.isChangeEnabled(
OVERRIDE_CAMERA_ROTATE_AND_CROP_DEFAULTS, packageName,
UserHandle.getUserHandleForUid(taskInfo.userId)))) {
@@ -673,12 +657,6 @@ public class CameraServiceProxy extends SystemService
CameraStatsJobService.schedule(mContext);
try {
- ActivityTaskManager.getService().registerTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to register task stack listener!");
- }
-
- try {
int[] displayIds = WindowManagerGlobal.getWindowManagerService()
.registerDisplayWindowListener(mDisplayWindowListener);
for (int i = 0; i < displayIds.length; i++) {
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 155b61891d12..737b653318d2 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -177,7 +177,7 @@ public class LocationProviderManager extends
protected interface LocationTransport {
void deliverOnLocationChanged(LocationResult locationResult,
- @Nullable Runnable onCompleteCallback) throws Exception;
+ @Nullable IRemoteCallback onCompleteCallback) throws Exception;
void deliverOnFlushComplete(int requestCode) throws Exception;
}
@@ -197,9 +197,8 @@ public class LocationProviderManager extends
@Override
public void deliverOnLocationChanged(LocationResult locationResult,
- @Nullable Runnable onCompleteCallback) throws RemoteException {
- mListener.onLocationChanged(locationResult.asList(),
- SingleUseCallback.wrap(onCompleteCallback));
+ @Nullable IRemoteCallback onCompleteCallback) throws RemoteException {
+ mListener.onLocationChanged(locationResult.asList(), onCompleteCallback);
}
@Override
@@ -227,7 +226,7 @@ public class LocationProviderManager extends
@Override
public void deliverOnLocationChanged(LocationResult locationResult,
- @Nullable Runnable onCompleteCallback)
+ @Nullable IRemoteCallback onCompleteCallback)
throws PendingIntent.CanceledException {
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setDontSendToRestrictedApps(true);
@@ -243,20 +242,34 @@ public class LocationProviderManager extends
intent.putExtra(KEY_LOCATIONS, locationResult.asList().toArray(new Location[0]));
}
+ PendingIntent.OnFinished onFinished = null;
+
// send() SHOULD only run the completion callback if it completes successfully. however,
- // b/199464864 (which could not be fixed in the S timeframe) means that it's possible
+ // b/201299281 (which could not be fixed in the S timeframe) means that it's possible
// for send() to throw an exception AND run the completion callback. if this happens, we
// would over-release the wakelock... we take matters into our own hands to ensure that
// the completion callback can only be run if send() completes successfully. this means
// the completion callback may be run inline - but as we've never specified what thread
// the callback is run on, this is fine.
- GatedCallback gatedCallback = new GatedCallback(onCompleteCallback);
+ GatedCallback gatedCallback;
+ if (onCompleteCallback != null) {
+ gatedCallback = new GatedCallback(() -> {
+ try {
+ onCompleteCallback.sendResult(null);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ });
+ onFinished = (pI, i, rC, rD, rE) -> gatedCallback.run();
+ } else {
+ gatedCallback = new GatedCallback(null);
+ }
mPendingIntent.send(
mContext,
0,
intent,
- (pI, i, rC, rD, rE) -> gatedCallback.run(),
+ onFinished,
null,
null,
options.toBundle());
@@ -293,7 +306,7 @@ public class LocationProviderManager extends
@Override
public void deliverOnLocationChanged(@Nullable LocationResult locationResult,
- @Nullable Runnable onCompleteCallback)
+ @Nullable IRemoteCallback onCompleteCallback)
throws RemoteException {
// ILocationCallback doesn't currently support completion callbacks
Preconditions.checkState(onCompleteCallback == null);
@@ -714,6 +727,13 @@ public class LocationProviderManager extends
final PowerManager.WakeLock mWakeLock;
+ // b/206340085 - if we allocate a new wakelock releaser object for every delivery we
+ // increase the risk of resource starvation. if a client stops processing deliveries the
+ // system server binder allocation pool will be starved as we continue to queue up
+ // deliveries, each with a new allocation. in order to mitigate this, we use a single
+ // releaser object per registration rather than per delivery.
+ final ExternalWakeLockReleaser mWakeLockReleaser;
+
private volatile ProviderTransport mProviderTransport;
private int mNumLocationsDelivered = 0;
private long mExpirationRealtimeMs = Long.MAX_VALUE;
@@ -727,6 +747,7 @@ public class LocationProviderManager extends
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
mWakeLock.setReferenceCounted(true);
mWakeLock.setWorkSource(request.getWorkSource());
+ mWakeLockReleaser = new ExternalWakeLockReleaser(identity, mWakeLock);
}
@Override
@@ -943,7 +964,7 @@ public class LocationProviderManager extends
}
listener.deliverOnLocationChanged(deliverLocationResult,
- mUseWakeLock ? mWakeLock::release : null);
+ mUseWakeLock ? mWakeLockReleaser : null);
EVENT_LOG.logProviderDeliveredLocations(mName, locationResult.size(),
getIdentity());
}
@@ -2761,7 +2782,7 @@ public class LocationProviderManager extends
@GuardedBy("this")
private boolean mRun;
- GatedCallback(Runnable callback) {
+ GatedCallback(@Nullable Runnable callback) {
mCallback = callback;
}
@@ -2796,4 +2817,24 @@ public class LocationProviderManager extends
}
}
}
+
+ private static class ExternalWakeLockReleaser extends IRemoteCallback.Stub {
+
+ private final CallerIdentity mIdentity;
+ private final PowerManager.WakeLock mWakeLock;
+
+ ExternalWakeLockReleaser(CallerIdentity identity, PowerManager.WakeLock wakeLock) {
+ mIdentity = identity;
+ mWakeLock = Objects.requireNonNull(wakeLock);
+ }
+
+ @Override
+ public void sendResult(Bundle data) {
+ try {
+ mWakeLock.release();
+ } catch (RuntimeException e) {
+ Log.e(TAG, "wakelock over-released by " + mIdentity, e);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b469a80a3a2f..393d101e9830 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -160,6 +160,7 @@ import static com.android.server.wm.ActivityRecordProto.NUM_DRAWN_WINDOWS;
import static com.android.server.wm.ActivityRecordProto.NUM_INTERESTING_WINDOWS;
import static com.android.server.wm.ActivityRecordProto.PIP_AUTO_ENTER_ENABLED;
import static com.android.server.wm.ActivityRecordProto.PROC_ID;
+import static com.android.server.wm.ActivityRecordProto.PROVIDES_MAX_BOUNDS;
import static com.android.server.wm.ActivityRecordProto.REPORTED_DRAWN;
import static com.android.server.wm.ActivityRecordProto.REPORTED_VISIBLE;
import static com.android.server.wm.ActivityRecordProto.STARTING_DISPLAYED;
@@ -261,6 +262,7 @@ import android.content.Intent;
import android.content.LocusId;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ConstrainDisplayApisConfig;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -596,6 +598,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*/
private CompatDisplayInsets mCompatDisplayInsets;
+ private static ConstrainDisplayApisConfig sConstrainDisplayApisConfig;
+
boolean pendingVoiceInteractionStart; // Waiting for activity-invoked voice session
IVoiceInteractionSession voiceSession; // Voice interaction session for this activity
@@ -1162,8 +1166,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (info.configChanges != 0) {
pw.println(prefix + "configChanges=0x" + Integer.toHexString(info.configChanges));
}
- pw.println(prefix + "neverSandboxDisplayApis=" + info.neverSandboxDisplayApis());
- pw.println(prefix + "alwaysSandboxDisplayApis=" + info.alwaysSandboxDisplayApis());
+ pw.println(prefix + "neverSandboxDisplayApis=" + info.neverSandboxDisplayApis(
+ sConstrainDisplayApisConfig));
+ pw.println(prefix + "alwaysSandboxDisplayApis=" + info.alwaysSandboxDisplayApis(
+ sConstrainDisplayApisConfig));
}
if (mLastParentBeforePip != null) {
pw.println(prefix + "lastParentTaskIdBeforePip=" + mLastParentBeforePip.mTaskId);
@@ -1769,6 +1775,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
info.windowLayout.windowLayoutAffinity =
uid + ":" + info.windowLayout.windowLayoutAffinity;
}
+ // Initialize once, when we know all system services are available.
+ if (sConstrainDisplayApisConfig == null) {
+ sConstrainDisplayApisConfig = new ConstrainDisplayApisConfig();
+ }
stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
nonLocalizedLabel = aInfo.nonLocalizedLabel;
labelRes = aInfo.labelRes;
@@ -7465,8 +7475,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
+ "should create compatDisplayInsets = %s",
getUid(),
mTmpBounds,
- info.neverSandboxDisplayApis(),
- info.alwaysSandboxDisplayApis(),
+ info.neverSandboxDisplayApis(sConstrainDisplayApisConfig),
+ info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig),
!matchParentBounds(),
mCompatDisplayInsets != null,
shouldCreateCompatDisplayInsets());
@@ -8027,11 +8037,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
// Never apply sandboxing to an app that should be explicitly excluded from the config.
- if (info != null && info.neverSandboxDisplayApis()) {
+ if (info.neverSandboxDisplayApis(sConstrainDisplayApisConfig)) {
return false;
}
// Always apply sandboxing to an app that should be explicitly included from the config.
- if (info != null && info.alwaysSandboxDisplayApis()) {
+ if (info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig)) {
return true;
}
// Max bounds should be sandboxed when an activity should have compatDisplayInsets, and it
@@ -9047,6 +9057,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled());
proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode());
proto.write(MIN_ASPECT_RATIO, getMinAspectRatio());
+ // Only record if max bounds sandboxing is applied, if the caller has the necessary
+ // permission to access the device configs.
+ proto.write(PROVIDES_MAX_BOUNDS, providesMaxBounds());
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 2cf23c5e6f7f..436a325559e6 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -72,6 +72,8 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
+import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
+import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY;
import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME;
import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
@@ -1275,7 +1277,7 @@ class ActivityStarter {
// This is used to block background activity launch even if the app is still
// visible to user after user clicking home button.
- final boolean appSwitchAllowed = mService.getBalAppSwitchesAllowed();
+ final int appSwitchState = mService.getBalAppSwitchesState();
// don't abort if the callingUid has a visible window or is a persistent system process
final int callingUidProcState = mService.mActiveUids.getUidState(callingUid);
@@ -1288,7 +1290,9 @@ class ActivityStarter {
// Normal apps with visible app window will be allowed to start activity if app switching
// is allowed, or apps like live wallpaper with non app visible window will be allowed.
- if (((appSwitchAllowed || mService.mActiveUids.hasNonAppVisibleWindow(callingUid))
+ final boolean appSwitchAllowedOrFg =
+ appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY;
+ if (((appSwitchAllowedOrFg || mService.mActiveUids.hasNonAppVisibleWindow(callingUid))
&& callingUidHasAnyVisibleWindow)
|| isCallingUidPersistentSystemProcess) {
if (DEBUG_ACTIVITY_STARTS) {
@@ -1398,7 +1402,7 @@ class ActivityStarter {
// don't abort if the callerApp or other processes of that uid are allowed in any way
if (callerApp != null) {
// first check the original calling process
- if (callerApp.areBackgroundActivityStartsAllowed(appSwitchAllowed)) {
+ if (callerApp.areBackgroundActivityStartsAllowed(appSwitchState)) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Background activity start allowed: callerApp process (pid = "
+ callerApp.getPid() + ", uid = " + callerAppUid + ") is allowed");
@@ -1412,7 +1416,7 @@ class ActivityStarter {
for (int i = uidProcesses.size() - 1; i >= 0; i--) {
final WindowProcessController proc = uidProcesses.valueAt(i);
if (proc != callerApp
- && proc.areBackgroundActivityStartsAllowed(appSwitchAllowed)) {
+ && proc.areBackgroundActivityStartsAllowed(appSwitchState)) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG,
"Background activity start allowed: process " + proc.getPid()
@@ -1426,7 +1430,7 @@ class ActivityStarter {
// anything that has fallen through would currently be aborted
Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage
+ "; callingUid: " + callingUid
- + "; appSwitchAllowed: " + appSwitchAllowed
+ + "; appSwitchState: " + appSwitchState
+ "; isCallingUidForeground: " + isCallingUidForeground
+ "; callingUidHasAnyVisibleWindow: " + callingUidHasAnyVisibleWindow
+ "; callingUidProcState: " + DebugUtils.valueToString(ActivityManager.class,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 60a514e4d612..c8227d953009 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -504,7 +504,27 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
* Whether normal application switches are allowed; a call to {@link #stopAppSwitches()
* disables this.
*/
- private volatile boolean mAppSwitchesAllowed = true;
+ private volatile int mAppSwitchesState = APP_SWITCH_ALLOW;
+
+ // The duration of resuming foreground app switch from disallow.
+ private static final long RESUME_FG_APP_SWITCH_MS = 500;
+
+ /** App switch is not allowed. */
+ static final int APP_SWITCH_DISALLOW = 0;
+
+ /** App switch is allowed only if the activity launch was requested by a foreground app. */
+ static final int APP_SWITCH_FG_ONLY = 1;
+
+ /** App switch is allowed. */
+ static final int APP_SWITCH_ALLOW = 2;
+
+ @IntDef({
+ APP_SWITCH_DISALLOW,
+ APP_SWITCH_FG_ONLY,
+ APP_SWITCH_ALLOW,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface AppSwitchState {}
/**
* Last stop app switches time, apps finished before this time cannot start background activity
@@ -1247,7 +1267,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (topFocusedRootTask != null && topFocusedRootTask.getTopResumedActivity() != null
&& topFocusedRootTask.getTopResumedActivity().info.applicationInfo.uid
== Binder.getCallingUid()) {
- mAppSwitchesAllowed = true;
+ mAppSwitchesState = APP_SWITCH_ALLOW;
}
}
return pir.sendInner(0, fillInIntent, resolvedType, allowlistToken, null, null,
@@ -2158,8 +2178,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
/**
* Return true if app switching is allowed.
*/
- boolean getBalAppSwitchesAllowed() {
- return mAppSwitchesAllowed;
+ @AppSwitchState int getBalAppSwitchesState() {
+ return mAppSwitchesState;
}
/** Register an {@link AnrController} to control the ANR dialog behavior */
@@ -3680,8 +3700,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public void stopAppSwitches() {
mAmInternal.enforceCallingPermission(STOP_APP_SWITCHES, "stopAppSwitches");
synchronized (mGlobalLock) {
- mAppSwitchesAllowed = false;
+ mAppSwitchesState = APP_SWITCH_DISALLOW;
mLastStopAppSwitchesTime = SystemClock.uptimeMillis();
+ mH.removeMessages(H.RESUME_FG_APP_SWITCH_MSG);
+ mH.sendEmptyMessageDelayed(H.RESUME_FG_APP_SWITCH_MSG, RESUME_FG_APP_SWITCH_MS);
}
}
@@ -3689,7 +3711,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public void resumeAppSwitches() {
mAmInternal.enforceCallingPermission(STOP_APP_SWITCHES, "resumeAppSwitches");
synchronized (mGlobalLock) {
- mAppSwitchesAllowed = true;
+ mAppSwitchesState = APP_SWITCH_ALLOW;
+ mH.removeMessages(H.RESUME_FG_APP_SWITCH_MSG);
}
}
@@ -5170,6 +5193,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
static final int REPORT_TIME_TRACKER_MSG = 1;
static final int UPDATE_PROCESS_ANIMATING_STATE = 2;
static final int END_POWER_MODE_UNKNOWN_VISIBILITY_MSG = 3;
+ static final int RESUME_FG_APP_SWITCH_MSG = 4;
static final int FIRST_ACTIVITY_TASK_MSG = 100;
static final int FIRST_SUPERVISOR_TASK_MSG = 200;
@@ -5207,6 +5231,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
break;
+ case RESUME_FG_APP_SWITCH_MSG: {
+ synchronized (mGlobalLock) {
+ if (mAppSwitchesState == APP_SWITCH_DISALLOW) {
+ mAppSwitchesState = APP_SWITCH_FG_ONLY;
+ }
+ }
+ }
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
index 71a10df34d30..0afd87282783 100644
--- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
+++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java
@@ -20,6 +20,8 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVIT
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS;
+import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
+import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -70,13 +72,13 @@ class BackgroundLaunchProcessController {
}
boolean areBackgroundActivityStartsAllowed(int pid, int uid, String packageName,
- boolean appSwitchAllowed, boolean isCheckingForFgsStart,
+ int appSwitchState, boolean isCheckingForFgsStart,
boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges,
long lastStopAppSwitchesTime, long lastActivityLaunchTime,
long lastActivityFinishTime) {
// If app switching is not allowed, we ignore all the start activity grace period
// exception so apps cannot start itself in onPause() after pressing home button.
- if (appSwitchAllowed) {
+ if (appSwitchState == APP_SWITCH_ALLOW) {
// Allow if any activity in the caller has either started or finished very recently, and
// it must be started or finished after last stop app switches time.
final long now = SystemClock.uptimeMillis();
@@ -111,7 +113,8 @@ class BackgroundLaunchProcessController {
return true;
}
// Allow if the caller has an activity in any foreground task.
- if (appSwitchAllowed && hasActivityInVisibleTask) {
+ if (hasActivityInVisibleTask
+ && (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "[Process(" + pid
+ ")] Activity start allowed: process has activity in foreground task");
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index 94a175caba22..8a2d11636fe3 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -251,15 +251,47 @@ public class LockTaskController {
*/
boolean activityBlockedFromFinish(ActivityRecord activity) {
final Task task = activity.getTask();
- if (activity == task.getRootActivity()
- && activity == task.getTopNonFinishingActivity()
- && task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV
- && isRootTask(task)) {
- Slog.i(TAG, "Not finishing task in lock task mode");
- showLockTaskToast();
- return true;
+ if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV || !isRootTask(task)) {
+ return false;
}
- return false;
+
+ final ActivityRecord taskTop = task.getTopNonFinishingActivity();
+ final ActivityRecord taskRoot = task.getRootActivity();
+ // If task has more than one Activity, verify if there's only adjacent TaskFragments that
+ // should be finish together in the Task.
+ if (activity != taskRoot || activity != taskTop) {
+ final TaskFragment taskFragment = activity.getTaskFragment();
+ final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
+ if (taskFragment.asTask() != null
+ || !taskFragment.isDelayLastActivityRemoval()
+ || adjacentTaskFragment == null) {
+ // Don't block activity from finishing if the TaskFragment don't have any adjacent
+ // TaskFragment, or it won't finish together with its adjacent TaskFragment.
+ return false;
+ }
+
+ final boolean hasOtherActivityInTaskFragment =
+ taskFragment.getActivity(a -> !a.finishing && a != activity) != null;
+ if (hasOtherActivityInTaskFragment) {
+ // Don't block activity from finishing if there's other Activity in the same
+ // TaskFragment.
+ return false;
+ }
+
+ final boolean hasOtherActivityInTask = task.getActivity(a -> !a.finishing
+ && a != activity && a.getTaskFragment() != adjacentTaskFragment) != null;
+ if (hasOtherActivityInTask) {
+ // Do not block activity from finishing if there are another running activities
+ // after the current and adjacent TaskFragments are removed. Note that we don't
+ // check activities in adjacent TaskFragment because it will be finished together
+ // with TaskFragment regardless of numbers of activities.
+ return false;
+ }
+ }
+
+ Slog.i(TAG, "Not finishing task in lock task mode");
+ showLockTaskToast();
+ return true;
}
/**
diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
index b54208d11974..9ad30da1cb54 100644
--- a/services/core/java/com/android/server/wm/PinnedTaskController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -255,25 +255,27 @@ class PinnedTaskController {
mDestRotatedBounds = null;
mPipTransaction = null;
final Rect areaBounds = taskArea.getBounds();
- if (pipTx != null) {
+ if (pipTx != null && pipTx.mPosition != null) {
// The transaction from recents animation is in old rotation. So the position needs to
// be rotated.
- float dx = pipTx.mPositionX;
- float dy = pipTx.mPositionY;
+ float dx = pipTx.mPosition.x;
+ float dy = pipTx.mPosition.y;
final Matrix matrix = pipTx.getMatrix();
if (pipTx.mRotation == 90) {
- dx = pipTx.mPositionY;
- dy = areaBounds.right - pipTx.mPositionX;
+ dx = pipTx.mPosition.y;
+ dy = areaBounds.right - pipTx.mPosition.x;
matrix.postRotate(-90);
} else if (pipTx.mRotation == -90) {
- dx = areaBounds.bottom - pipTx.mPositionY;
- dy = pipTx.mPositionX;
+ dx = areaBounds.bottom - pipTx.mPosition.y;
+ dy = pipTx.mPosition.x;
matrix.postRotate(90);
}
matrix.postTranslate(dx, dy);
final SurfaceControl leash = pinnedTask.getSurfaceControl();
- t.setMatrix(leash, matrix, new float[9])
- .setCornerRadius(leash, pipTx.mCornerRadius);
+ t.setMatrix(leash, matrix, new float[9]);
+ if (pipTx.hasCornerRadiusSet()) {
+ t.setCornerRadius(leash, pipTx.mCornerRadius);
+ }
Slog.i(TAG, "Seamless rotation PiP tx=" + pipTx + " pos=" + dx + "," + dy);
return;
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index fd4b63e26403..5dd8ef39e8e7 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -264,13 +264,6 @@ public class RecentsAnimationController implements DeathRecipient {
"finish(%b): mCanceled=%b", moveHomeToTop, mCanceled);
final long token = Binder.clearCallingIdentity();
try {
- synchronized (mService.getWindowManagerLock()) {
- // Remove all new task targets.
- for (int i = mPendingNewTaskTargets.size() - 1; i >= 0; i--) {
- removeTaskInternal(mPendingNewTaskTargets.get(i));
- }
- }
-
// Note, the callback will handle its own synchronization, do not lock on WM lock
// prior to calling the callback
mCallbacks.onAnimationFinished(moveHomeToTop
@@ -760,7 +753,7 @@ public class RecentsAnimationController implements DeathRecipient {
// the task-id with the leaf id.
final Task leafTask = task.getTopLeafTask();
int taskId = leafTask.mTaskId;
- TaskAnimationAdapter adapter = (TaskAnimationAdapter) addAnimation(task,
+ TaskAnimationAdapter adapter = addAnimation(task,
!recentTaskIds.get(taskId), true /* hidden */, finishedCallback);
mPendingNewTaskTargets.add(taskId);
return adapter.createRemoteAnimationTarget(taskId);
@@ -1013,6 +1006,7 @@ public class RecentsAnimationController implements DeathRecipient {
taskAdapter.onCleanup();
}
// Should already be empty, but clean-up pending task-appears in-case they weren't sent.
+ mPendingNewTaskTargets.clear();
mPendingTaskAppears.clear();
for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f0a15543a22e..c88dbf719d94 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -321,6 +321,11 @@ class Task extends TaskFragment {
*/
boolean mInResumeTopActivity = false;
+ /**
+ * Used to identify if the activity that is installed from device's system image.
+ */
+ boolean mIsEffectivelySystemApp;
+
int mCurrentUser;
String affinity; // The affinity name for this task, or null; may change identity.
@@ -568,13 +573,24 @@ class Task extends TaskFragment {
if (r.finishing) return false;
- // Set this as the candidate root since it isn't finishing.
- mRoot = r;
+ if (mRoot == null || mRoot.finishing) {
+ // Set this as the candidate root since it isn't finishing.
+ mRoot = r;
+ }
+
+ final int uid = mRoot == r ? effectiveUid : r.info.applicationInfo.uid;
+ if (ignoreRelinquishIdentity
+ || (mRoot.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0
+ || (mRoot.info.applicationInfo.uid != Process.SYSTEM_UID
+ && !mRoot.info.applicationInfo.isSystemApp()
+ && mRoot.info.applicationInfo.uid != uid)) {
+ // No need to relinquish identity, end search.
+ return true;
+ }
- // Only end search if we are ignore relinquishing identity or we are not relinquishing.
- return ignoreRelinquishIdentity
- || mNeverRelinquishIdentity
- || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
+ // Relinquish to next activity
+ mRoot = r;
+ return false;
}
}
@@ -999,7 +1015,15 @@ class Task extends TaskFragment {
* @param info The activity info which could be different from {@code r.info} if set.
*/
void setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info) {
- if (this.intent == null || !mNeverRelinquishIdentity) {
+ boolean updateIdentity = false;
+ if (this.intent == null) {
+ updateIdentity = true;
+ } else if (!mNeverRelinquishIdentity) {
+ final ActivityInfo activityInfo = info != null ? info : r.info;
+ updateIdentity = (effectiveUid == Process.SYSTEM_UID || mIsEffectivelySystemApp
+ || effectiveUid == activityInfo.applicationInfo.uid);
+ }
+ if (updateIdentity) {
mCallingUid = r.launchedFromUid;
mCallingPackage = r.launchedFromPackage;
mCallingFeatureId = r.launchedFromFeatureId;
@@ -1012,14 +1036,7 @@ class Task extends TaskFragment {
private void setIntent(Intent _intent, ActivityInfo info) {
if (!isLeafTask()) return;
- if (info.applicationInfo.uid == Process.SYSTEM_UID
- || info.applicationInfo.isSystemApp()) {
- // Only allow the apps that pre-installed on the system image to apply
- // relinquishTaskIdentity
- mNeverRelinquishIdentity = (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
- } else {
- mNeverRelinquishIdentity = true;
- }
+ mNeverRelinquishIdentity = (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
affinity = info.taskAffinity;
if (intent == null) {
// If this task already has an intent associated with it, don't set the root
@@ -1028,6 +1045,7 @@ class Task extends TaskFragment {
rootAffinity = affinity;
}
effectiveUid = info.applicationInfo.uid;
+ mIsEffectivelySystemApp = info.applicationInfo.isSystemApp();
stringName = null;
if (info.targetActivity == null) {
@@ -3141,14 +3159,6 @@ class Task extends TaskFragment {
}
@Override
- boolean fillsParent() {
- // From the perspective of policy, we still want to report that this task fills parent
- // in fullscreen windowing mode even it doesn't match parent bounds because there will be
- // letterbox around its real content.
- return getWindowingMode() == WINDOWING_MODE_FULLSCREEN || matchParentBounds();
- }
-
- @Override
void forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
final int count = mChildren.size();
boolean isLeafTask = true;
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 7bcf8a9f274f..916fa5be12d8 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -241,7 +241,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
/**
* Whether to delay the last activity of TaskFragment being immediately removed while finishing.
* This should only be set on a embedded TaskFragment, where the organizer can have the
- * opportunity to perform other actions or animations.
+ * opportunity to perform animations and finishing the adjacent TaskFragment.
*/
private boolean mDelayLastActivityRemoval;
@@ -2346,6 +2346,14 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return true;
}
+ @Override
+ boolean fillsParent() {
+ // From the perspective of policy, we still want to report that this task fills parent
+ // in fullscreen windowing mode even it doesn't match parent bounds because there will be
+ // letterbox around its real content.
+ return getWindowingMode() == WINDOWING_MODE_FULLSCREEN || matchParentBounds();
+ }
+
boolean dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll,
boolean dumpClient, String dumpPackage, final boolean needSep, Runnable header) {
boolean printed = false;
diff --git a/services/core/java/com/android/server/wm/WindowContextListenerController.java b/services/core/java/com/android/server/wm/WindowContextListenerController.java
index cc527136eb51..7956a112539e 100644
--- a/services/core/java/com/android/server/wm/WindowContextListenerController.java
+++ b/services/core/java/com/android/server/wm/WindowContextListenerController.java
@@ -173,7 +173,7 @@ class WindowContextListenerController {
@VisibleForTesting
class WindowContextListenerImpl implements WindowContainerListener {
- @NonNull private final IBinder mClientToken;
+ @NonNull private final IWindowToken mClientToken;
private final int mOwnerUid;
@NonNull private WindowContainer<?> mContainer;
/**
@@ -193,7 +193,7 @@ class WindowContextListenerController {
private WindowContextListenerImpl(IBinder clientToken, WindowContainer<?> container,
int ownerUid, @WindowType int type, @Nullable Bundle options) {
- mClientToken = clientToken;
+ mClientToken = IWindowToken.Stub.asInterface(clientToken);
mContainer = Objects.requireNonNull(container);
mOwnerUid = ownerUid;
mType = type;
@@ -205,7 +205,7 @@ class WindowContextListenerController {
mDeathRecipient = deathRecipient;
} catch (RemoteException e) {
ProtoLog.e(WM_ERROR, "Could not register window container listener token=%s, "
- + "container=%s", mClientToken, mContainer);
+ + "container=%s", clientToken, mContainer);
}
}
@@ -228,17 +228,17 @@ class WindowContextListenerController {
}
private void register() {
+ final IBinder token = mClientToken.asBinder();
if (mDeathRecipient == null) {
- throw new IllegalStateException("Invalid client token: " + mClientToken);
+ throw new IllegalStateException("Invalid client token: " + token);
}
- mListeners.putIfAbsent(mClientToken, this);
+ mListeners.putIfAbsent(token, this);
mContainer.registerWindowContainerListener(this);
- reportConfigToWindowTokenClient();
}
private void unregister() {
mContainer.unregisterWindowContainerListener(this);
- mListeners.remove(mClientToken);
+ mListeners.remove(mClientToken.asBinder());
}
private void clear() {
@@ -258,19 +258,24 @@ class WindowContextListenerController {
private void reportConfigToWindowTokenClient() {
if (mDeathRecipient == null) {
- throw new IllegalStateException("Invalid client token: " + mClientToken);
+ throw new IllegalStateException("Invalid client token: " + mClientToken.asBinder());
+ }
+ final DisplayContent dc = mContainer.getDisplayContent();
+ if (!dc.isReady()) {
+ // Do not report configuration when booting. The latest configuration will be sent
+ // when WindowManagerService#displayReady().
+ return;
}
// If the display of window context associated window container is suspended, don't
// report the configuration update. Note that we still dispatch the configuration update
// to WindowProviderService to make it compatible with Service#onConfigurationChanged.
// Service always receives #onConfigurationChanged callback regardless of display state.
- if (!isWindowProviderService(mOptions)
- && isSuspendedState(mContainer.getDisplayContent().getDisplayInfo().state)) {
+ if (!isWindowProviderService(mOptions) && isSuspendedState(dc.getDisplayInfo().state)) {
mHasPendingConfiguration = true;
return;
}
final Configuration config = mContainer.getConfiguration();
- final int displayId = mContainer.getDisplayContent().getDisplayId();
+ final int displayId = dc.getDisplayId();
if (mLastReportedConfig == null) {
mLastReportedConfig = new Configuration();
}
@@ -282,9 +287,8 @@ class WindowContextListenerController {
mLastReportedConfig.setTo(config);
mLastReportedDisplay = displayId;
- IWindowToken windowTokenClient = IWindowToken.Stub.asInterface(mClientToken);
try {
- windowTokenClient.onConfigurationChanged(config, displayId);
+ mClientToken.onConfigurationChanged(config, displayId);
} catch (RemoteException e) {
ProtoLog.w(WM_ERROR, "Could not report config changes to the window token client.");
}
@@ -294,7 +298,7 @@ class WindowContextListenerController {
@Override
public void onRemoved() {
if (mDeathRecipient == null) {
- throw new IllegalStateException("Invalid client token: " + mClientToken);
+ throw new IllegalStateException("Invalid client token: " + mClientToken.asBinder());
}
final WindowToken windowToken = mContainer.asWindowToken();
if (windowToken != null && windowToken.isFromClient()) {
@@ -312,9 +316,8 @@ class WindowContextListenerController {
}
}
mDeathRecipient.unlinkToDeath();
- IWindowToken windowTokenClient = IWindowToken.Stub.asInterface(mClientToken);
try {
- windowTokenClient.onWindowTokenRemoved();
+ mClientToken.onWindowTokenRemoved();
} catch (RemoteException e) {
ProtoLog.w(WM_ERROR, "Could not report token removal to the window token client.");
}
@@ -323,7 +326,7 @@ class WindowContextListenerController {
@Override
public String toString() {
- return "WindowContextListenerImpl{clientToken=" + mClientToken + ", "
+ return "WindowContextListenerImpl{clientToken=" + mClientToken.asBinder() + ", "
+ "container=" + mContainer + "}";
}
@@ -337,11 +340,11 @@ class WindowContextListenerController {
}
void linkToDeath() throws RemoteException {
- mClientToken.linkToDeath(this, 0);
+ mClientToken.asBinder().linkToDeath(this, 0);
}
void unlinkToDeath() {
- mClientToken.unlinkToDeath(this, 0);
+ mClientToken.asBinder().unlinkToDeath(this, 0);
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 1cfbe07d3f16..3ccb06ccef15 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -512,19 +512,19 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
*/
@HotPath(caller = HotPath.START_SERVICE)
public boolean areBackgroundFgsStartsAllowed() {
- return areBackgroundActivityStartsAllowed(mAtm.getBalAppSwitchesAllowed(),
+ return areBackgroundActivityStartsAllowed(mAtm.getBalAppSwitchesState(),
true /* isCheckingForFgsStart */);
}
- boolean areBackgroundActivityStartsAllowed(boolean appSwitchAllowed) {
- return areBackgroundActivityStartsAllowed(appSwitchAllowed,
+ boolean areBackgroundActivityStartsAllowed(int appSwitchState) {
+ return areBackgroundActivityStartsAllowed(appSwitchState,
false /* isCheckingForFgsStart */);
}
- private boolean areBackgroundActivityStartsAllowed(boolean appSwitchAllowed,
+ private boolean areBackgroundActivityStartsAllowed(int appSwitchState,
boolean isCheckingForFgsStart) {
return mBgLaunchController.areBackgroundActivityStartsAllowed(mPid, mUid, mInfo.packageName,
- appSwitchAllowed, isCheckingForFgsStart, hasActivityInVisibleTask(),
+ appSwitchState, isCheckingForFgsStart, hasActivityInVisibleTask(),
mInstrumentingWithBackgroundActivityStartPrivileges,
mAtm.getLastStopAppSwitchesTime(),
mLastActivityLaunchTime, mLastActivityFinishTime);
diff --git a/services/people/java/com/android/server/people/data/ConversationStatusExpirationBroadcastReceiver.java b/services/people/java/com/android/server/people/data/ConversationStatusExpirationBroadcastReceiver.java
index 49d5e50e0345..d3353cd6adc7 100644
--- a/services/people/java/com/android/server/people/data/ConversationStatusExpirationBroadcastReceiver.java
+++ b/services/people/java/com/android/server/people/data/ConversationStatusExpirationBroadcastReceiver.java
@@ -31,6 +31,7 @@ import android.os.CancellationSignal;
import com.android.server.LocalServices;
import com.android.server.people.PeopleServiceInternal;
+import com.android.server.pm.PackageManagerService;
/**
* If a {@link ConversationStatus} is added to the system with an expiration time, remove that
@@ -50,6 +51,7 @@ public class ConversationStatusExpirationBroadcastReceiver extends BroadcastRece
final PendingIntent pi = PendingIntent.getBroadcast(context,
REQUEST_CODE,
new Intent(ACTION)
+ .setPackage(PackageManagerService.PLATFORM_PACKAGE_NAME)
.setData(new Uri.Builder().scheme(SCHEME)
.appendPath(getKey(userId, pkg, conversationId, status))
.build())
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 18f1267b890f..0dd4f5b338b4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
@@ -1854,6 +1855,36 @@ public class MockingOomAdjusterTests {
@SuppressWarnings("GuardedBy")
@Test
+ public void testUpdateOomAdj_DoAll_BoundByPersService_Cycle_Branch_Capability() {
+ ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+ MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+ ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+ MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+ bindService(app, client, null, Context.BIND_INCLUDE_CAPABILITIES, mock(IBinder.class));
+ ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+ MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+ bindService(client, client2, null, Context.BIND_INCLUDE_CAPABILITIES, mock(IBinder.class));
+ bindService(client2, app, null, Context.BIND_INCLUDE_CAPABILITIES, mock(IBinder.class));
+ ProcessRecord client3 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
+ MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
+ client3.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+ bindService(app, client3, null, Context.BIND_INCLUDE_CAPABILITIES, mock(IBinder.class));
+ ArrayList<ProcessRecord> lru = sService.mProcessList.getLruProcessesLOSP();
+ lru.clear();
+ lru.add(app);
+ lru.add(client);
+ lru.add(client2);
+ lru.add(client3);
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ sService.mOomAdjuster.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+
+ assertEquals(PROCESS_CAPABILITY_ALL, client.mState.getSetCapability());
+ assertEquals(PROCESS_CAPABILITY_ALL, client2.mState.getSetCapability());
+ assertEquals(PROCESS_CAPABILITY_ALL, app.mState.getSetCapability());
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
public void testUpdateOomAdj_DoAll_Provider_Cycle_Branch_2() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index 4c638d669019..bb3eb81df6ed 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -16,6 +16,13 @@
<configuration description="Runs Frameworks Services Tests.">
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push-file" key="SimpleServiceTestApp3.apk"
+ value="/data/local/tmp/cts/content/SimpleServiceTestApp3.apk" />
+ </target_preparer>
+
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="install-arg" value="-t" />
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
index 8b6b7c235c44..1d6ed038b86d 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
@@ -296,14 +296,6 @@ public class SystemActionPerformerTest {
}
@Test
- public void testToggleSplitScreen_legacy() {
- setupWithRealContext();
- mSystemActionPerformer.performSystemAction(
- AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
- verify(mMockStatusBarManagerInternal).toggleSplitScreen();
- }
-
- @Test
public void testScreenshot_requestsFromScreenshotHelper_legacy() {
setupWithMockContext();
mSystemActionPerformer.performSystemAction(
diff --git a/services/tests/servicestests/src/com/android/server/am/ServiceRestarterTest.java b/services/tests/servicestests/src/com/android/server/am/ServiceRestarterTest.java
index 10f4c05eb6d8..e6a8dea973c9 100644
--- a/services/tests/servicestests/src/com/android/server/am/ServiceRestarterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ServiceRestarterTest.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -26,7 +27,9 @@ import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
+import android.os.IBinder;
import android.os.SystemClock;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
@@ -42,6 +45,8 @@ import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* Build/Install/Run:
@@ -69,6 +74,12 @@ public final class ServiceRestarterTest {
private static final int ACTION_STOPPKG = 8;
private static final int ACTION_ALL = ACTION_START | ACTION_KILL | ACTION_WAIT | ACTION_STOPPKG;
+ private static final String LOCAL_APK_BASE_PATH = "/data/local/tmp/cts/content/";
+ private static final String TEST_PACKAGE3_APK = "SimpleServiceTestApp3.apk";
+ private static final String ACTION_SERVICE_WITH_DEP_PKG =
+ "com.android.servicestests.apps.simpleservicetestapp.ACTION_SERVICE_WITH_DEP_PKG";
+ private static final String EXTRA_TARGET_PACKAGE = "target_package";
+
private Context mContext;
private Instrumentation mInstrumentation;
private int mTestPackage1Uid;
@@ -199,6 +210,83 @@ public final class ServiceRestarterTest {
return res;
}
+ @Test
+ public void testServiceWithDepPkgStopped() throws Exception {
+ final CountDownLatch[] latchHolder = new CountDownLatch[1];
+ final ServiceConnection conn = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ latchHolder[0].countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ latchHolder[0].countDown();
+ }
+ };
+
+ final long timeout = 5_000;
+ final long shortTimeout = 2_000;
+ final Intent intent = new Intent(ACTION_SERVICE_WITH_DEP_PKG);
+ final String testPkg = TEST_PACKAGE2_NAME;
+ final String libPkg = TEST_PACKAGE3_NAME;
+ final String apkPath = LOCAL_APK_BASE_PATH + TEST_PACKAGE3_APK;
+ final ActivityManager am = mContext.getSystemService(ActivityManager.class);
+
+ intent.setComponent(ComponentName.unflattenFromString(testPkg + "/" + TEST_SERVICE_NAME));
+ intent.putExtra(EXTRA_TARGET_PACKAGE, libPkg);
+ try {
+ executeShellCmd("am service-restart-backoff disable " + testPkg);
+
+ latchHolder[0] = new CountDownLatch(1);
+ assertTrue("Unable to bind to test service in " + testPkg,
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE));
+ assertTrue("Timed out to bind service in " + testPkg,
+ latchHolder[0].await(timeout, TimeUnit.MILLISECONDS));
+
+ Thread.sleep(shortTimeout);
+ assertTrue(libPkg + " should be a dependency package of " + testPkg,
+ isPackageDependency(testPkg, libPkg));
+
+ // Force-stop lib package, the test service should be restarted.
+ latchHolder[0] = new CountDownLatch(2);
+ am.forceStopPackage(libPkg);
+ assertTrue("Test service in didn't restart in " + testPkg,
+ latchHolder[0].await(timeout, TimeUnit.MILLISECONDS));
+
+ Thread.sleep(shortTimeout);
+
+ // Re-install the lib package, the test service should be restarted.
+ latchHolder[0] = new CountDownLatch(2);
+ assertTrue("Unable to install package " + apkPath, installPackage(apkPath));
+ assertTrue("Test service in didn't restart in " + testPkg,
+ latchHolder[0].await(timeout, TimeUnit.MILLISECONDS));
+
+ Thread.sleep(shortTimeout);
+
+ // Force-stop the service package, the test service should not be restarted.
+ latchHolder[0] = new CountDownLatch(2);
+ am.forceStopPackage(testPkg);
+ assertFalse("Test service should not be restarted in " + testPkg,
+ latchHolder[0].await(timeout * 2, TimeUnit.MILLISECONDS));
+ } finally {
+ executeShellCmd("am service-restart-backoff enable " + testPkg);
+ mContext.unbindService(conn);
+ am.forceStopPackage(testPkg);
+ }
+ }
+
+ private boolean isPackageDependency(String pkgName, String libPackage) throws Exception {
+ final String output = SystemUtil.runShellCommand("dumpsys activity processes " + pkgName);
+ final Matcher matcher = Pattern.compile("packageDependencies=\\{.*?\\b"
+ + libPackage + "\\b.*?\\}").matcher(output);
+ return matcher.find();
+ }
+
+ private boolean installPackage(String apkPath) throws Exception {
+ return executeShellCmd("pm install -t " + apkPath).equals("Success\n");
+ }
+
private void startServiceAndWait(String pkgName, MyUidImportanceListener uidListener,
long timeout) throws Exception {
final Intent intent = new Intent();
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml
index 78afb7b72c04..3cc105ebb746 100644
--- a/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml
@@ -18,6 +18,7 @@
package="com.android.servicestests.apps.simpleservicetestapp">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<application>
<service android:name=".SimpleService"
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleService.java b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleService.java
index 4e981b22cd32..b8654d7f4e74 100644
--- a/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleService.java
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleService.java
@@ -17,8 +17,10 @@ package com.android.servicestests.apps.simpleservicetestapp;
import android.app.Service;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IRemoteCallback;
@@ -33,6 +35,9 @@ public class SimpleService extends Service {
private static final String TEST_CLASS =
"com.android.servicestests.apps.simpleservicetestapp.SimpleService";
+ private static final String ACTION_SERVICE_WITH_DEP_PKG =
+ "com.android.servicestests.apps.simpleservicetestapp.ACTION_SERVICE_WITH_DEP_PKG";
+
private static final String EXTRA_CALLBACK = "callback";
private static final String EXTRA_COMMAND = "command";
private static final String EXTRA_FLAGS = "flags";
@@ -118,6 +123,21 @@ public class SimpleService extends Service {
@Override
public IBinder onBind(Intent intent) {
+ if (ACTION_SERVICE_WITH_DEP_PKG.equals(intent.getAction())) {
+ final String targetPkg = intent.getStringExtra(EXTRA_TARGET_PACKAGE);
+ Log.i(TAG, "SimpleService.onBind: " + ACTION_SERVICE_WITH_DEP_PKG + " " + targetPkg);
+ if (targetPkg != null) {
+ Context pkgContext = null;
+ try {
+ pkgContext = createPackageContext(targetPkg,
+ Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Unable to create package context for " + pkgContext, e);
+ }
+ // This effectively loads the target package as a dependency.
+ pkgContext.getClassLoader();
+ }
+ }
return mBinder;
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 8c1045d995d6..bfaa8150cb99 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -899,22 +899,21 @@ public class TaskTests extends WindowTestsBase {
/**
* Test that root activity index is reported correctly when looking for the 'effective root' in
- * case when bottom activity is finishing. Ignore the relinquishing task identity if it's not a
- * system activity even with the FLAG_RELINQUISH_TASK_IDENTITY.
+ * case when bottom activities are relinquishing task identity or finishing.
*/
@Test
public void testFindRootIndex_effectiveRoot_finishingAndRelinquishing() {
- final Task task = getTestTask();
+ final ActivityRecord activity0 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final Task task = activity0.getTask();
// Add extra two activities. Mark the one on the bottom with "relinquishTaskIdentity" and
// one above as finishing.
- final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
activity1.finishing = true;
new ActivityBuilder(mAtm).setTask(task).build();
assertEquals("The first non-finishing activity and non-relinquishing task identity "
- + "must be reported.", task.getChildAt(0), task.getRootActivity(
+ + "must be reported.", task.getChildAt(2), task.getRootActivity(
false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
}
@@ -934,21 +933,21 @@ public class TaskTests extends WindowTestsBase {
}
/**
- * Test that the root activity index is reported correctly when looking for the
- * 'effective root' for the case when all non-system activities have relinquishTaskIdentity set.
+ * Test that the topmost activity index is reported correctly when looking for the
+ * 'effective root' for the case when all activities have relinquishTaskIdentity set.
*/
@Test
public void testFindRootIndex_effectiveRoot_relinquishingMultipleActivities() {
- final Task task = getTestTask();
+ final ActivityRecord activity0 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final Task task = activity0.getTask();
// Set relinquishTaskIdentity for all activities in the task
- final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
- assertEquals("The topmost activity in the task must be reported.", task.getChildAt(0),
- task.getRootActivity(false /*ignoreRelinquishIdentity*/,
- true /*setToBottomIfNone*/));
+ assertEquals("The topmost activity in the task must be reported.",
+ task.getChildAt(task.getChildCount() - 1), task.getRootActivity(
+ false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
}
/** Test that bottom-most activity is reported in {@link Task#getRootActivity()}. */
@@ -1086,14 +1085,14 @@ public class TaskTests extends WindowTestsBase {
}
/**
- * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} with non-system
- * activity that relinquishes task identity.
+ * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} with activity that
+ * relinquishes task identity.
*/
@Test
public void testGetTaskForActivity_onlyRoot_relinquishTaskIdentity() {
- final Task task = getTestTask();
+ final ActivityRecord activity0 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final Task task = activity0.getTask();
// Make the current root activity relinquish task identity
- final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
// Add an extra activity on top - this will be the new root
final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
@@ -1102,7 +1101,7 @@ public class TaskTests extends WindowTestsBase {
assertEquals(task.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
- assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID,
+ assertEquals(task.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity1.appToken, true /* onlyRoot */));
assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID,
ActivityRecord.getTaskForActivityLocked(activity2.appToken, true /* onlyRoot */));
@@ -1189,6 +1188,46 @@ public class TaskTests extends WindowTestsBase {
verify(task).setIntent(eq(activity0));
}
+ /**
+ * Test {@link Task#updateEffectiveIntent()} when activity with relinquishTaskIdentity but
+ * another with different uid. This should make the task use the root activity when updating the
+ * intent.
+ */
+ @Test
+ public void testUpdateEffectiveIntent_relinquishingWithDifferentUid() {
+ final ActivityRecord activity0 = new ActivityBuilder(mAtm)
+ .setActivityFlags(FLAG_RELINQUISH_TASK_IDENTITY).setCreateTask(true).build();
+ final Task task = activity0.getTask();
+
+ // Add an extra activity on top
+ new ActivityBuilder(mAtm).setUid(11).setTask(task).build();
+
+ spyOn(task);
+ task.updateEffectiveIntent();
+ verify(task).setIntent(eq(activity0));
+ }
+
+ /**
+ * Test {@link Task#updateEffectiveIntent()} with activities set as relinquishTaskIdentity.
+ * This should make the task use the topmost activity when updating the intent.
+ */
+ @Test
+ public void testUpdateEffectiveIntent_relinquishingMultipleActivities() {
+ final ActivityRecord activity0 = new ActivityBuilder(mAtm)
+ .setActivityFlags(FLAG_RELINQUISH_TASK_IDENTITY).setCreateTask(true).build();
+ final Task task = activity0.getTask();
+ // Add an extra activity on top
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+ activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+
+ // Add an extra activity on top
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
+
+ spyOn(task);
+ task.updateEffectiveIntent();
+ verify(task).setIntent(eq(activity2));
+ }
+
@Test
public void testSaveLaunchingStateWhenConfigurationChanged() {
LaunchParamsPersister persister = mAtm.mTaskSupervisor.mLaunchParamsPersister;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 9c9e41b64892..b8a14b8ea72e 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -5794,6 +5794,7 @@ public class CarrierConfigManager {
sDefaults.putInt(
KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG,
120000);
+ sDefaults.putAll(ImsServiceEntitlement.getDefaults());
sDefaults.putAll(Gps.getDefaults());
sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
new int[] {