summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt18
-rw-r--r--core/api/test-current.txt4
-rw-r--r--core/java/android/app/ActivityManagerInternal.java19
-rw-r--r--core/java/android/app/WallpaperInfo.java34
-rw-r--r--core/java/android/hardware/display/DisplayManager.java17
-rw-r--r--core/java/android/service/voice/IVoiceInteractionSession.aidl2
-rw-r--r--core/java/android/service/voice/VisibleActivityInfo.aidl19
-rw-r--r--core/java/android/service/voice/VisibleActivityInfo.java205
-rw-r--r--core/java/android/service/voice/VoiceInteractionManagerInternal.java1
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java167
-rw-r--r--core/java/android/util/MathUtils.java4
-rw-r--r--core/java/android/view/View.java3
-rw-r--r--core/java/android/view/ViewRootImpl.java16
-rw-r--r--core/java/android/view/animation/Animation.java11
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java1
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl10
-rw-r--r--core/java/com/android/internal/os/WifiPowerCalculator.java3
-rw-r--r--core/res/res/values-pa/strings.xml2
-rw-r--r--core/res/res/values-te/strings.xml6
-rw-r--r--core/res/res/values/attrs.xml23
-rw-r--r--core/res/res/values/config.xml7
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java40
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java14
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java53
-rw-r--r--libs/hwui/pipeline/skia/RenderNodeDrawable.cpp3
-rw-r--r--packages/PrintSpooler/res/values-te/strings.xml4
-rw-r--r--packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java7
-rw-r--r--packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml10
-rw-r--r--packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java36
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java16
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java31
-rw-r--r--packages/SystemUI/animation/res/anim/launch_host_dialog_enter.xml23
-rw-r--r--packages/SystemUI/animation/res/anim/launch_host_dialog_exit.xml22
-rw-r--r--packages/SystemUI/animation/res/values/ids.xml19
-rw-r--r--packages/SystemUI/animation/res/values/styles.xml29
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt385
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt16
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt541
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt94
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java112
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt355
-rw-r--r--packages/SystemUI/res-keyguard/drawable/ic_backspace_24dp.xml2
-rw-r--r--packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values/styles.xml7
-rw-r--r--packages/SystemUI/res/drawable/media_output_dialog_background.xml23
-rw-r--r--packages/SystemUI/res/layout/internet_connectivity_dialog.xml2
-rw-r--r--packages/SystemUI/res/layout/media_output_dialog.xml2
-rw-r--r--packages/SystemUI/res/layout/media_view.xml1
-rw-r--r--packages/SystemUI/res/values-af/strings.xml1
-rw-r--r--packages/SystemUI/res/values-am/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml1
-rw-r--r--packages/SystemUI/res/values-as/strings.xml1
-rw-r--r--packages/SystemUI/res/values-az/strings.xml1
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml1
-rw-r--r--packages/SystemUI/res/values-be/strings.xml1
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml1
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml1
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml1
-rw-r--r--packages/SystemUI/res/values-da/strings.xml1
-rw-r--r--packages/SystemUI/res/values-de/strings.xml1
-rw-r--r--packages/SystemUI/res/values-el/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml1
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml1
-rw-r--r--packages/SystemUI/res/values-es/strings.xml1
-rw-r--r--packages/SystemUI/res/values-et/strings.xml1
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml3
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml1
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml1
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml1
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml1
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml1
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml1
-rw-r--r--packages/SystemUI/res/values-in/strings.xml1
-rw-r--r--packages/SystemUI/res/values-is/strings.xml1
-rw-r--r--packages/SystemUI/res/values-it/strings.xml1
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml1
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-km/strings.xml1
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml1
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml1
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml1
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml1
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml1
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml1
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml1
-rw-r--r--packages/SystemUI/res/values-my/strings.xml1
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml1
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-or/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml1
-rw-r--r--packages/SystemUI/res/values-si/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml3
-rw-r--r--packages/SystemUI/res/values-sw600dp/dimens.xml4
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml1
-rw-r--r--packages/SystemUI/res/values-te/strings.xml1
-rw-r--r--packages/SystemUI/res/values-th/strings.xml1
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml1
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml1
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml1
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml1
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml1
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml1
-rw-r--r--packages/SystemUI/res/values/colors.xml2
-rw-r--r--packages/SystemUI/res/values/dimens.xml4
-rw-r--r--packages/SystemUI/res/values/styles.xml7
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadButton.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt186
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java4
-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.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt7
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java26
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java42
-rw-r--r--services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java60
-rw-r--r--services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java80
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java179
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java55
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java15
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java9
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java13
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java158
-rw-r--r--services/core/java/com/android/server/wm/AnimationAdapter.java11
-rw-r--r--services/core/java/com/android/server/wm/AppTaskImpl.java10
-rw-r--r--services/core/java/com/android/server/wm/LocalAnimationAdapter.java11
-rw-r--r--services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java62
-rw-r--r--services/core/java/com/android/server/wm/RemoteAnimationController.java43
-rw-r--r--services/core/java/com/android/server/wm/SurfaceFreezer.java18
-rw-r--r--services/core/java/com/android/server/wm/Task.java4
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java3
-rw-r--r--services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java9
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimationSpec.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java39
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java31
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java12
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java109
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java146
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java152
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java61
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java35
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java52
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java38
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java161
211 files changed, 3797 insertions, 1057 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 4df648cb7009..9a16390baf10 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1298,7 +1298,7 @@ package android {
field public static final int shortcutLongLabel = 16844074; // 0x101052a
field public static final int shortcutShortLabel = 16844073; // 0x1010529
field public static final int shouldDisableView = 16843246; // 0x10101ee
- field public static final int shouldUseDefaultUnfoldTransition;
+ field public static final int shouldUseDefaultDeviceStateChangeTransition;
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
@@ -6927,7 +6927,7 @@ package android.app {
method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
method public CharSequence loadLabel(android.content.pm.PackageManager);
method public android.graphics.drawable.Drawable loadThumbnail(android.content.pm.PackageManager);
- method public boolean shouldUseDefaultUnfoldTransition();
+ method public boolean shouldUseDefaultDeviceStateChangeTransition();
method public boolean supportsMultipleDisplays();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.WallpaperInfo> CREATOR;
@@ -39001,6 +39001,13 @@ package android.service.textservice {
package android.service.voice {
+ public final class VisibleActivityInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.service.voice.VoiceInteractionSession.ActivityId getActivityId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.VisibleActivityInfo> CREATOR;
+ }
+
public class VoiceInteractionService extends android.app.Service {
ctor public VoiceInteractionService();
method public int getDisabledShowContext();
@@ -39062,6 +39069,7 @@ package android.service.voice {
method public void onTaskStarted(android.content.Intent, int);
method public void onTrimMemory(int);
method public final void performDirectAction(@NonNull android.app.DirectAction, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.os.Bundle>);
+ method public final void registerVisibleActivityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.service.voice.VoiceInteractionSession.VisibleActivityCallback);
method public final void requestDirectActions(@NonNull android.service.voice.VoiceInteractionSession.ActivityId, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.app.DirectAction>>);
method public void setContentView(android.view.View);
method public void setDisabledShowContext(int);
@@ -39071,6 +39079,7 @@ package android.service.voice {
method public void show(android.os.Bundle, int);
method public void startAssistantActivity(android.content.Intent);
method public void startVoiceActivity(android.content.Intent);
+ method public final void unregisterVisibleActivityCallback(@NonNull android.service.voice.VoiceInteractionSession.VisibleActivityCallback);
field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10
field public static final int SHOW_SOURCE_APPLICATION = 8; // 0x8
field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4
@@ -39144,6 +39153,11 @@ package android.service.voice {
method public boolean isActive();
}
+ public static interface VoiceInteractionSession.VisibleActivityCallback {
+ method public default void onInvisible(@NonNull android.service.voice.VoiceInteractionSession.ActivityId);
+ method public default void onVisible(@NonNull android.service.voice.VisibleActivityInfo);
+ }
+
public abstract class VoiceInteractionSessionService extends android.app.Service {
ctor public VoiceInteractionSessionService();
method public android.os.IBinder onBind(android.content.Intent);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 2ecf088fb5d0..d484100373af 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2391,6 +2391,10 @@ package android.service.voice {
method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[]);
}
+ public final class VisibleActivityInfo implements android.os.Parcelable {
+ ctor public VisibleActivityInfo(int, @NonNull android.os.IBinder);
+ }
+
}
package android.service.watchdog {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 70bb132c7668..f8c8aa32a26e 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -652,4 +652,23 @@ public abstract class ActivityManagerInternal {
public abstract int sendIntentSender(IIntentSender target, IBinder allowlistToken, int code,
Intent intent, String resolvedType,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options);
+
+ /**
+ * Sets the provider to communicate between voice interaction manager service and
+ * ActivityManagerService.
+ */
+ public abstract void setVoiceInteractionManagerProvider(
+ @Nullable VoiceInteractionManagerProvider provider);
+
+ /**
+ * Provides the interface to communicate between voice interaction manager service and
+ * ActivityManagerService.
+ */
+ public interface VoiceInteractionManagerProvider {
+ /**
+ * Notifies the service when a high-level activity event has been changed, for example,
+ * an activity was resumed or stopped.
+ */
+ void notifyActivityEventChanged();
+ }
}
diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java
index 4dff4e0e84d6..c552cb62749b 100644
--- a/core/java/android/app/WallpaperInfo.java
+++ b/core/java/android/app/WallpaperInfo.java
@@ -81,7 +81,7 @@ public final class WallpaperInfo implements Parcelable {
final int mContextDescriptionResource;
final boolean mShowMetadataInPreview;
final boolean mSupportsAmbientMode;
- final boolean mShouldUseDefaultUnfoldTransition;
+ final boolean mShouldUseDefaultDeviceStateChangeTransition;
final String mSettingsSliceUri;
final boolean mSupportMultipleDisplays;
@@ -146,9 +146,9 @@ public final class WallpaperInfo implements Parcelable {
mSupportsAmbientMode = sa.getBoolean(
com.android.internal.R.styleable.Wallpaper_supportsAmbientMode,
false);
- mShouldUseDefaultUnfoldTransition = sa.getBoolean(
- com.android.internal.R.styleable.Wallpaper_shouldUseDefaultUnfoldTransition,
- true);
+ mShouldUseDefaultDeviceStateChangeTransition = sa.getBoolean(
+ com.android.internal.R.styleable
+ .Wallpaper_shouldUseDefaultDeviceStateChangeTransition, true);
mSettingsSliceUri = sa.getString(
com.android.internal.R.styleable.Wallpaper_settingsSliceUri);
mSupportMultipleDisplays = sa.getBoolean(
@@ -175,7 +175,7 @@ public final class WallpaperInfo implements Parcelable {
mSupportsAmbientMode = source.readInt() != 0;
mSettingsSliceUri = source.readString();
mSupportMultipleDisplays = source.readInt() != 0;
- mShouldUseDefaultUnfoldTransition = source.readInt() != 0;
+ mShouldUseDefaultDeviceStateChangeTransition = source.readInt() != 0;
mService = ResolveInfo.CREATOR.createFromParcel(source);
}
@@ -399,23 +399,25 @@ public final class WallpaperInfo implements Parcelable {
}
/**
- * Returns whether this wallpaper should receive default zooming updates when unfolding.
- * If set to false the wallpaper will not receive zoom events when folding or unfolding
- * a foldable device, so it can implement its own unfold transition.
+ * Returns whether this wallpaper should receive default zooming updates when the device
+ * changes its state (e.g. when folding or unfolding a foldable device).
+ * If set to false the wallpaper will not receive zoom events when changing the device state,
+ * so it can implement its own transition instead.
* <p>
* This corresponds to the value {@link
- * android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition} in the XML description
- * of the wallpaper.
+ * android.R.styleable#Wallpaper_shouldUseDefaultDeviceStateChangeTransition} in the
+ * XML description of the wallpaper.
* <p>
* The default value is {@code true}.
*
- * @see android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition
- * @return {@code true} if wallpaper should receive default fold/unfold transition updates
+ * @see android.R.styleable#Wallpaper_shouldUseDefaultDeviceStateChangeTransition
+ * @return {@code true} if wallpaper should receive default device state change
+ * transition updates
*
- * @attr ref android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition
+ * @attr ref android.R.styleable#Wallpaper_shouldUseDefaultDeviceStateChangeTransition
*/
- public boolean shouldUseDefaultUnfoldTransition() {
- return mShouldUseDefaultUnfoldTransition;
+ public boolean shouldUseDefaultDeviceStateChangeTransition() {
+ return mShouldUseDefaultDeviceStateChangeTransition;
}
public void dump(Printer pw, String prefix) {
@@ -448,7 +450,7 @@ public final class WallpaperInfo implements Parcelable {
dest.writeInt(mSupportsAmbientMode ? 1 : 0);
dest.writeString(mSettingsSliceUri);
dest.writeInt(mSupportMultipleDisplays ? 1 : 0);
- dest.writeInt(mShouldUseDefaultUnfoldTransition ? 1 : 0);
+ dest.writeInt(mShouldUseDefaultDeviceStateChangeTransition ? 1 : 0);
mService.writeToParcel(dest, flags);
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 73961ff373dd..d8f20391098c 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -1288,6 +1288,23 @@ public final class DisplayManager {
*/
String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS =
"fixed_refresh_rate_high_ambient_brightness_thresholds";
+
+ /**
+ * Key for refresh rate when the device is in high brightness mode for sunlight visility.
+ *
+ * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+ * @see android.R.integer#config_defaultRefreshRateInHbmSunlight
+ */
+ String KEY_REFRESH_RATE_IN_HBM_SUNLIGHT = "refresh_rate_in_hbm_sunlight";
+
+ /**
+ * Key for refresh rate when the device is in high brightness mode for HDR.
+ *
+ * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+ * @see android.R.integer#config_defaultRefreshRateInHbmHdr
+ */
+ String KEY_REFRESH_RATE_IN_HBM_HDR = "refresh_rate_in_hbm_hdr";
+
/**
* Key for default peak refresh rate
*
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index c142a53e047e..59f1e8eed89c 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -22,6 +22,7 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.IBinder;
+import android.service.voice.VisibleActivityInfo;
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
@@ -39,4 +40,5 @@ oneway interface IVoiceInteractionSession {
void closeSystemDialogs();
void onLockscreenShown();
void destroy();
+ void updateVisibleActivityInfo(in VisibleActivityInfo visibleActivityInfo, int type);
}
diff --git a/core/java/android/service/voice/VisibleActivityInfo.aidl b/core/java/android/service/voice/VisibleActivityInfo.aidl
new file mode 100644
index 000000000000..34bd57c15456
--- /dev/null
+++ b/core/java/android/service/voice/VisibleActivityInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.service.voice;
+
+parcelable VisibleActivityInfo;
diff --git a/core/java/android/service/voice/VisibleActivityInfo.java b/core/java/android/service/voice/VisibleActivityInfo.java
new file mode 100644
index 000000000000..139544c76a50
--- /dev/null
+++ b/core/java/android/service/voice/VisibleActivityInfo.java
@@ -0,0 +1,205 @@
+/*
+ * 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 android.service.voice;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.os.CancellationSignal;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * The class is used to represent a visible activity information. The system provides this to
+ * services that need to know {@link android.service.voice.VoiceInteractionSession.ActivityId}.
+ */
+@DataClass(
+ genConstructor = false,
+ genEqualsHashCode = true,
+ genHiddenConstDefs = false,
+ genGetters = false,
+ genToString = true
+)
+public final class VisibleActivityInfo implements Parcelable {
+
+ /**
+ * Indicates that it is a new visible activity.
+ *
+ * @hide
+ */
+ public static final int TYPE_ACTIVITY_ADDED = 1;
+
+ /**
+ * Indicates that it has become a invisible activity.
+ *
+ * @hide
+ */
+ public static final int TYPE_ACTIVITY_REMOVED = 2;
+
+ /**
+ * The identifier of the task this activity is in.
+ */
+ private final int mTaskId;
+
+ /**
+ * Token for targeting this activity for assist purposes.
+ */
+ @NonNull
+ private final IBinder mAssistToken;
+
+ /** @hide */
+ @TestApi
+ public VisibleActivityInfo(
+ int taskId,
+ @NonNull IBinder assistToken) {
+ Objects.requireNonNull(assistToken);
+ mTaskId = taskId;
+ mAssistToken = assistToken;
+ }
+
+ /**
+ * Returns the {@link android.service.voice.VoiceInteractionSession.ActivityId} of this
+ * visible activity which can be used to interact with an activity, for example through
+ * {@link VoiceInteractionSession#requestDirectActions(VoiceInteractionSession.ActivityId,
+ * CancellationSignal, Executor, Consumer)}.
+ */
+ public @NonNull VoiceInteractionSession.ActivityId getActivityId() {
+ return new VoiceInteractionSession.ActivityId(mTaskId, mAssistToken);
+ }
+
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/voice/VisibleActivityInfo.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "VisibleActivityInfo { " +
+ "taskId = " + mTaskId + ", " +
+ "assistToken = " + mAssistToken +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public boolean equals(@Nullable Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(VisibleActivityInfo other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ VisibleActivityInfo that = (VisibleActivityInfo) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && mTaskId == that.mTaskId
+ && Objects.equals(mAssistToken, that.mAssistToken);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int hashCode() {
+ // You can override field hashCode logic by defining methods like:
+ // int fieldNameHashCode() { ... }
+
+ int _hash = 1;
+ _hash = 31 * _hash + mTaskId;
+ _hash = 31 * _hash + Objects.hashCode(mAssistToken);
+ return _hash;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeInt(mTaskId);
+ dest.writeStrongBinder(mAssistToken);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ VisibleActivityInfo(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ int taskId = in.readInt();
+ IBinder assistToken = (IBinder) in.readStrongBinder();
+
+ this.mTaskId = taskId;
+ this.mAssistToken = assistToken;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mAssistToken);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<VisibleActivityInfo> CREATOR
+ = new Parcelable.Creator<VisibleActivityInfo>() {
+ @Override
+ public VisibleActivityInfo[] newArray(int size) {
+ return new VisibleActivityInfo[size];
+ }
+
+ @Override
+ public VisibleActivityInfo createFromParcel(@NonNull Parcel in) {
+ return new VisibleActivityInfo(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1632383555284L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/core/java/android/service/voice/VisibleActivityInfo.java",
+ inputSignatures = "public static final int TYPE_ACTIVITY_ADDED\npublic static final int TYPE_ACTIVITY_REMOVED\nprivate final int mTaskId\nprivate final @android.annotation.NonNull android.os.IBinder mAssistToken\npublic @android.annotation.NonNull android.service.voice.VoiceInteractionSession.ActivityId getActivityId()\nclass VisibleActivityInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genEqualsHashCode=true, genHiddenConstDefs=false, genGetters=false, genToString=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/service/voice/VoiceInteractionManagerInternal.java b/core/java/android/service/voice/VoiceInteractionManagerInternal.java
index c048286545c3..c80640910bc2 100644
--- a/core/java/android/service/voice/VoiceInteractionManagerInternal.java
+++ b/core/java/android/service/voice/VoiceInteractionManagerInternal.java
@@ -22,7 +22,6 @@ import android.os.IBinder;
import com.android.internal.annotations.Immutable;
-
/**
* @hide
* Private interface to the VoiceInteractionManagerService for use by ActivityManagerService.
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 725e20f2a74d..9db856a8762a 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -74,9 +74,11 @@ import com.android.internal.util.function.pooled.PooledLambda;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -177,6 +179,10 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
ICancellationSignal mKillCallback;
+ private final Map<VisibleActivityCallback, Executor> mVisibleActivityCallbacks =
+ new ArrayMap<>();
+ private final List<VisibleActivityInfo> mVisibleActivityInfos = new ArrayList<>();
+
final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() {
@Override
public IVoiceInteractorRequest startConfirmation(String callingPackage,
@@ -352,6 +358,13 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
public void destroy() {
mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DESTROY));
}
+
+ @Override
+ public void updateVisibleActivityInfo(VisibleActivityInfo visibleActivityInfo, int type) {
+ mHandlerCaller.sendMessage(
+ mHandlerCaller.obtainMessageIO(MSG_UPDATE_VISIBLE_ACTIVITY_INFO, type,
+ visibleActivityInfo));
+ }
};
/**
@@ -843,6 +856,9 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
static final int MSG_SHOW = 106;
static final int MSG_HIDE = 107;
static final int MSG_ON_LOCKSCREEN_SHOWN = 108;
+ static final int MSG_UPDATE_VISIBLE_ACTIVITY_INFO = 109;
+ static final int MSG_REGISTER_VISIBLE_ACTIVITY_CALLBACK = 110;
+ static final int MSG_UNREGISTER_VISIBLE_ACTIVITY_CALLBACK = 111;
class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
@Override
@@ -928,6 +944,27 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
if (DEBUG) Log.d(TAG, "onLockscreenShown");
onLockscreenShown();
break;
+ case MSG_UPDATE_VISIBLE_ACTIVITY_INFO:
+ if (DEBUG) {
+ Log.d(TAG, "doUpdateVisibleActivityInfo: visibleActivityInfo=" + msg.obj
+ + " type=" + msg.arg1);
+ }
+ doUpdateVisibleActivityInfo((VisibleActivityInfo) msg.obj, msg.arg1);
+ break;
+ case MSG_REGISTER_VISIBLE_ACTIVITY_CALLBACK:
+ if (DEBUG) {
+ Log.d(TAG, "doRegisterVisibleActivityCallback");
+ }
+ args = (SomeArgs) msg.obj;
+ doRegisterVisibleActivityCallback((Executor) args.arg1,
+ (VisibleActivityCallback) args.arg2);
+ break;
+ case MSG_UNREGISTER_VISIBLE_ACTIVITY_CALLBACK:
+ if (DEBUG) {
+ Log.d(TAG, "doUnregisterVisibleActivityCallback");
+ }
+ doUnregisterVisibleActivityCallback((VisibleActivityCallback) msg.obj);
+ break;
}
if (args != null) {
args.recycle();
@@ -1122,6 +1159,86 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
}
}
+ private void doUpdateVisibleActivityInfo(VisibleActivityInfo visibleActivityInfo, int type) {
+
+ if (mVisibleActivityCallbacks.isEmpty()) {
+ return;
+ }
+
+ switch (type) {
+ case VisibleActivityInfo.TYPE_ACTIVITY_ADDED:
+ informVisibleActivityChanged(visibleActivityInfo, type);
+ mVisibleActivityInfos.add(visibleActivityInfo);
+ break;
+ case VisibleActivityInfo.TYPE_ACTIVITY_REMOVED:
+ informVisibleActivityChanged(visibleActivityInfo, type);
+ mVisibleActivityInfos.remove(visibleActivityInfo);
+ break;
+ }
+ }
+
+ private void doRegisterVisibleActivityCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull VisibleActivityCallback callback) {
+ if (mVisibleActivityCallbacks.containsKey(callback)) {
+ if (DEBUG) {
+ Log.d(TAG, "doRegisterVisibleActivityCallback: callback has registered");
+ }
+ return;
+ }
+
+ int preCallbackCount = mVisibleActivityCallbacks.size();
+ mVisibleActivityCallbacks.put(callback, executor);
+
+ if (preCallbackCount == 0) {
+ try {
+ mSystemService.startListeningVisibleActivityChanged(mToken);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ } else {
+ for (int i = 0; i < mVisibleActivityInfos.size(); i++) {
+ final VisibleActivityInfo visibleActivityInfo = mVisibleActivityInfos.get(i);
+ executor.execute(() -> callback.onVisible(visibleActivityInfo));
+ }
+ }
+ }
+
+ private void doUnregisterVisibleActivityCallback(@NonNull VisibleActivityCallback callback) {
+ mVisibleActivityCallbacks.remove(callback);
+
+ if (mVisibleActivityCallbacks.size() == 0) {
+ mVisibleActivityInfos.clear();
+ try {
+ mSystemService.stopListeningVisibleActivityChanged(mToken);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ private void informVisibleActivityChanged(VisibleActivityInfo visibleActivityInfo, int type) {
+ for (Map.Entry<VisibleActivityCallback, Executor> e :
+ mVisibleActivityCallbacks.entrySet()) {
+ final Executor executor = e.getValue();
+ final VisibleActivityCallback visibleActivityCallback = e.getKey();
+
+ switch (type) {
+ case VisibleActivityInfo.TYPE_ACTIVITY_ADDED:
+ Binder.withCleanCallingIdentity(() -> {
+ executor.execute(
+ () -> visibleActivityCallback.onVisible(visibleActivityInfo));
+ });
+ break;
+ case VisibleActivityInfo.TYPE_ACTIVITY_REMOVED:
+ Binder.withCleanCallingIdentity(() -> {
+ executor.execute(() -> visibleActivityCallback.onInvisible(
+ visibleActivityInfo.getActivityId()));
+ });
+ break;
+ }
+ }
+ }
+
void ensureWindowCreated() {
if (mInitialized) {
return;
@@ -1926,6 +2043,45 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
}
/**
+ * Registers a callback that will be notified when visible activities have been changed.
+ *
+ * @param executor The handler to receive the callback.
+ * @param callback The callback to receive the response.
+ *
+ * @throws IllegalStateException if calling this method before onCreate().
+ */
+ public final void registerVisibleActivityCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull VisibleActivityCallback callback) {
+ if (DEBUG) {
+ Log.d(TAG, "registerVisibleActivityCallback");
+ }
+ if (mToken == null) {
+ throw new IllegalStateException("Can't call before onCreate()");
+ }
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ mHandlerCaller.sendMessage(
+ mHandlerCaller.obtainMessageOO(MSG_REGISTER_VISIBLE_ACTIVITY_CALLBACK, executor,
+ callback));
+ }
+
+ /**
+ * Unregisters the callback.
+ *
+ * @param callback The callback to receive the response.
+ */
+ public final void unregisterVisibleActivityCallback(@NonNull VisibleActivityCallback callback) {
+ if (DEBUG) {
+ Log.d(TAG, "unregisterVisibleActivityCallback");
+ }
+ Objects.requireNonNull(callback);
+
+ mHandlerCaller.sendMessage(
+ mHandlerCaller.obtainMessageO(MSG_UNREGISTER_VISIBLE_ACTIVITY_CALLBACK, callback));
+ }
+
+ /**
* Print the Service's state into the given stream. This gets invoked by
* {@link VoiceInteractionSessionService} when its Service
* {@link android.app.Service#dump} method is called.
@@ -1975,6 +2131,17 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
}
/**
+ * Callback interface for receiving visible activity changes used for assistant usage.
+ */
+ public interface VisibleActivityCallback {
+ /** Callback to inform that an activity has become visible. */
+ default void onVisible(@NonNull VisibleActivityInfo activityInfo) {}
+
+ /** Callback to inform that a visible activity has gone. */
+ default void onInvisible(@NonNull ActivityId activityId) {}
+ }
+
+ /**
* Represents assist state captured when this session was started.
* It contains the various assist data objects and a reference to
* the source activity.
diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java
index 971e16185815..aecde4415117 100644
--- a/core/java/android/util/MathUtils.java
+++ b/core/java/android/util/MathUtils.java
@@ -165,6 +165,10 @@ public final class MathUtils {
return start + (stop - start) * amount;
}
+ public static float lerp(int start, int stop, float amount) {
+ return lerp((float) start, (float) stop, amount);
+ }
+
/**
* Returns the interpolation scalar (s) that satisfies the equation: {@code value = }{@link
* #lerp}{@code (a, b, s)}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index afdb755179a6..b729c9fb01b1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -20889,13 +20889,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED;
}
+ notifyAppearedOrDisappearedForContentCaptureIfNeeded(false);
+
mAttachInfo = null;
if (mOverlay != null) {
mOverlay.getOverlayView().dispatchDetachedFromWindow();
}
notifyEnterOrExitForAutoFillIfNeeded(false);
- notifyAppearedOrDisappearedForContentCaptureIfNeeded(false);
}
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 20888f75b55f..c45b27a8a2c2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2864,8 +2864,13 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ final boolean surfaceControlChanged =
+ (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED)
+ == RELAYOUT_RES_SURFACE_CHANGED;
+
if (mSurfaceControl.isValid()) {
- updateOpacity(mWindowAttributes, dragResizing);
+ updateOpacity(mWindowAttributes, dragResizing,
+ surfaceControlChanged /*forceUpdate */);
}
if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
@@ -2900,9 +2905,7 @@ public final class ViewRootImpl implements ViewParent,
// RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new
// SurfaceControl.
surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId()
- || (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED)
- == RELAYOUT_RES_SURFACE_CHANGED)
- && mSurface.isValid();
+ || surfaceControlChanged) && mSurface.isValid();
if (surfaceReplaced) {
mSurfaceSequenceId++;
}
@@ -7895,7 +7898,8 @@ public final class ViewRootImpl implements ViewParent,
return relayoutResult;
}
- private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing) {
+ private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing,
+ boolean forceUpdate) {
boolean opaque = false;
if (!PixelFormat.formatHasAlpha(params.format)
@@ -7911,7 +7915,7 @@ public final class ViewRootImpl implements ViewParent,
opaque = true;
}
- if (mIsSurfaceOpaque == opaque) {
+ if (!forceUpdate && mIsSurfaceOpaque == opaque) {
return;
}
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 81e2f3ca98ec..b1d618eff40a 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -258,6 +258,8 @@ public abstract class Animation implements Cloneable {
setZAdjustment(a.getInt(com.android.internal.R.styleable.Animation_zAdjustment, ZORDER_NORMAL));
+ setBackgroundColor(a.getInt(com.android.internal.R.styleable.Animation_background, 0));
+
setDetachWallpaper(
a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false));
setShowWallpaper(
@@ -630,15 +632,16 @@ public abstract class Animation implements Cloneable {
}
/**
- * Set background behind an animation.
+ * Set background behind animation.
*
- * @param bg The background color. If 0, no background.
+ * @param bg The background color. If 0, no background. Currently must
+ * be black, with any desired alpha level.
*
* @deprecated None of window animations are running with background color.
*/
@Deprecated
public void setBackgroundColor(@ColorInt int bg) {
- mBackgroundColor = bg;
+ // The background color is not needed any more, do nothing.
}
/**
@@ -800,7 +803,7 @@ public abstract class Animation implements Cloneable {
@Deprecated
@ColorInt
public int getBackgroundColor() {
- return mBackgroundColor;
+ return 0;
}
/**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 42d77cd09689..e6f103e6d53b 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2154,6 +2154,7 @@ public final class InputMethodManager {
* @hide
*/
public boolean requestImeShow(IBinder windowToken) {
+ checkFocus();
synchronized (mH) {
final View servedView = getServedViewLocked();
if (servedView == null || servedView.getWindowToken() != windowToken) {
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index c8a4425409e8..998526209c72 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -272,4 +272,14 @@ interface IVoiceInteractionManagerService {
void triggerHardwareRecognitionEventForTest(
in SoundTrigger.KeyphraseRecognitionEvent event,
in IHotwordRecognitionStatusCallback callback);
+
+ /**
+ * Starts to listen the status of visible activity.
+ */
+ void startListeningVisibleActivityChanged(in IBinder token);
+
+ /**
+ * Stops to listen the status of visible activity.
+ */
+ void stopListeningVisibleActivityChanged(in IBinder token);
}
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index 776a70545df4..3915b0e01e7f 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -215,6 +215,9 @@ public class WifiPowerCalculator extends PowerCalculator {
+ "ms tx=" + txTime + "ms power=" + formatCharge(
powerDurationAndTraffic.powerMah));
}
+ } else {
+ powerDurationAndTraffic.durationMs = 0;
+ powerDurationAndTraffic.powerMah = 0;
}
} else {
final long wifiRunningTime = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 53eb2b7e87bf..7b80f606c99e 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -2010,7 +2010,7 @@
<string name="app_category_image" msgid="7307840291864213007">"ਫ਼ੋਟੋਆਂ ਅਤੇ ਚਿੱਤਰ"</string>
<string name="app_category_social" msgid="2278269325488344054">"ਸਮਾਜਕ ਅਤੇ ਸੰਚਾਰ"</string>
<string name="app_category_news" msgid="1172762719574964544">"ਖਬਰਾਂ ਅਤੇ ਰਸਾਲੇ"</string>
- <string name="app_category_maps" msgid="6395725487922533156">"ਨਕਸ਼ੇ ਅਤੇ ਆਵਾਗੌਣ"</string>
+ <string name="app_category_maps" msgid="6395725487922533156">"Maps ਅਤੇ ਨੈਵੀਗੇਸ਼ਨ"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ਉਤਪਾਦਕਤਾ"</string>
<string name="app_category_accessibility" msgid="6643521607848547683">"ਪਹੁੰਚਯੋਗਤਾ"</string>
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ਡੀਵਾਈਸ ਸਟੋਰੇਜ"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 680fbd2b7a24..a75ef3d9487c 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1043,7 +1043,7 @@
<string name="search_go" msgid="2141477624421347086">"సెర్చ్"</string>
<string name="search_hint" msgid="455364685740251925">"సెర్చ్ చేయండి..."</string>
<string name="searchview_description_search" msgid="1045552007537359343">"సెర్చ్"</string>
- <string name="searchview_description_query" msgid="7430242366971716338">"ప్రశ్నను వెతకండి"</string>
+ <string name="searchview_description_query" msgid="7430242366971716338">"సెర్చ్ క్వెరీ"</string>
<string name="searchview_description_clear" msgid="1989371719192982900">"ప్రశ్నను క్లియర్ చేయి"</string>
<string name="searchview_description_submit" msgid="6771060386117334686">"ప్రశ్నని సమర్పించండి"</string>
<string name="searchview_description_voice" msgid="42360159504884679">"వాయిస్ సెర్చ్"</string>
@@ -1412,7 +1412,7 @@
<string name="ext_media_new_notification_message" msgid="6095403121990786986">"సెటప్ చేయడానికి నొక్కండి"</string>
<string name="ext_media_new_notification_message" product="tv" msgid="216863352100263668">"సెటప్ చేయడానికి ఎంచుకోండి"</string>
<string name="ext_media_new_notification_message" product="automotive" msgid="5140127881613227162">"మీరు పరికరాన్ని తిరిగి ఫార్మాట్ చేయాల్సి ఉంటుంది. తొలగించడానికి ట్యాప్ చేయండి"</string>
- <string name="ext_media_ready_notification_message" msgid="777258143284919261">"ఫోటోలు మరియు మీడియాను బదిలీ చేయడానికి"</string>
+ <string name="ext_media_ready_notification_message" msgid="777258143284919261">"ఫోటోలు, మీడియాను బదిలీ చేయడానికి"</string>
<string name="ext_media_ready_notification_message" product="tv" msgid="8847134811163165935">"మీడియా ఫైల్స్‌ను బ్రౌజ్ చేయండి"</string>
<string name="ext_media_unmountable_notification_title" msgid="4895444667278979910">"<xliff:g id="NAME">%s</xliff:g>తో సమస్య ఉంది"</string>
<string name="ext_media_unmountable_notification_title" product="automotive" msgid="3142723758949023280">"<xliff:g id="NAME">%s</xliff:g> పని చేయటం లేదు"</string>
@@ -1524,7 +1524,7 @@
<string name="progress_erasing" msgid="6891435992721028004">"షేర్ చేసిన నిల్వను తొలగిస్తోంది…"</string>
<string name="share" msgid="4157615043345227321">"షేర్"</string>
<string name="find" msgid="5015737188624767706">"కనుగొనండి"</string>
- <string name="websearch" msgid="5624340204512793290">"వెబ్ శోధన"</string>
+ <string name="websearch" msgid="5624340204512793290">"వెబ్ సెర్చ్"</string>
<string name="find_next" msgid="5341217051549648153">"తదుపరిదాన్ని కనుగొను"</string>
<string name="find_previous" msgid="4405898398141275532">"మునుపటిదాన్ని కనుగొను"</string>
<string name="gpsNotifTicker" msgid="3207361857637620780">"<xliff:g id="NAME">%s</xliff:g> నుండి లొకేషన్ రిక్వెస్ట్‌"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9d90dd480203..53396407904a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -6822,8 +6822,9 @@
content for the duration of the animation. -->
<enum name="bottom" value="-1" />
</attr>
- <!-- Special background behind animation. Only for use with task animations.
- If 0, the default, there is no background. -->
+ <!-- Special background behind animation. Only for use with window
+ animations. Can only be a color, and only black. If 0, the
+ default, there is no background. -->
<attr name="background" />
<!-- Special option for window animations: if this window is on top
of a wallpaper, don't animate the wallpaper with it. -->
@@ -7736,7 +7737,7 @@
<!-- Name of a method on the Context used to inflate the menu that will be
called when the item is clicked.
- {@deprecated Menu actually traverses the Context hierarchy looking for the
+ {@deprecated Menu actually traverses the Context hierarchy looking for the
relevant method, which is fragile (an intermediate ContextWrapper adding a
same-named method would change behavior) and restricts bytecode optimizers
such as R8. Instead, use MenuItem.setOnMenuItemClickListener.} -->
@@ -8370,16 +8371,18 @@
@hide @SystemApi -->
<attr name="supportsAmbientMode" format="boolean" />
- <!-- Indicates that this wallpaper service should receive zoom updates when unfolding.
+ <!-- Indicates that this wallpaper service should receive zoom transition updates when
+ changing the device state (e.g. when folding or unfolding a foldable device).
When this value is set to true
{@link android.service.wallpaper.WallpaperService.Engine} could receive zoom updates
- when folding or unfolding a foldable device. Wallpapers receive zoom updates using
+ before or after changing the device state. Wallpapers receive zoom updates using
{@link android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float)} and
- zoom rendering should be handled manually. Default value is true.
- When set to false wallpapers can implement custom folding/unfolding behavior
- by listening to {@link android.hardware.Sensor#TYPE_HINGE_ANGLE}.
- Corresponds to {@link android.app.WallpaperInfo#shouldUseDefaultUnfoldTransition()} -->
- <attr name="shouldUseDefaultUnfoldTransition" format="boolean" />
+ zoom rendering should be handled manually. Zoom updates are delivered only when
+ {@link android.service.wallpaper.WallpaperService.Engine} is created and not destroyed.
+ Default value is true.
+ Corresponds to
+ {@link android.app.WallpaperInfo#shouldUseDefaultDeviceStateChangeTransition()} -->
+ <attr name="shouldUseDefaultDeviceStateChangeTransition" format="boolean" />
<!-- Uri that specifies a settings Slice for this wallpaper. -->
<attr name="settingsSliceUri" format="string"/>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cbe0eef6408b..689d75b9cfea 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4533,6 +4533,13 @@
If non-positive, then the refresh rate is unchanged even if thresholds are configured. -->
<integer name="config_fixedRefreshRateInHighZone">0</integer>
+ <!-- Default refresh rate while the device has high brightness mode enabled for Sunlight.
+ This value overrides values from DisplayDeviceConfig -->
+ <integer name="config_defaultRefreshRateInHbmSunlight">0</integer>
+
+ <!-- Default refresh rate while the device has high brightness mode enabled for HDR. -->
+ <integer name="config_defaultRefreshRateInHbmHdr">0</integer>
+
<!-- The type of the light sensor to be used by the display framework for things like
auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. -->
<string name="config_displayLightSensorType" translatable="false" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7d489049d112..e17daf09e4da 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3221,7 +3221,7 @@
<eat-comment />
<staging-public-group type="attr" first-id="0x01ff0000">
- <public name="shouldUseDefaultUnfoldTransition" />
+ <public name="shouldUseDefaultDeviceStateChangeTransition" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01fe0000">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index fbc629e2dc81..4e8d915ca295 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3964,6 +3964,8 @@
<java-symbol type="integer" name="config_defaultRefreshRateInZone" />
<java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" />
<java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" />
+ <java-symbol type="integer" name="config_defaultRefreshRateInHbmSunlight" />
+ <java-symbol type="integer" name="config_defaultRefreshRateInHbmHdr" />
<!-- For fixed refresh rate displays in high brightness-->
<java-symbol type="integer" name="config_fixedRefreshRateInHighZone" />
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
index 1e64782b161f..11a79b2f4a27 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
@@ -121,9 +121,11 @@ class TaskFragmentAnimationSpec {
* the second one is for the end leash.
*/
Animation[] createChangeBoundsChangeAnimations(@NonNull RemoteAnimationTarget target) {
+ // Both start bounds and end bounds are in screen coordinates. We will post translate
+ // to the local coordinates in TaskFragmentAnimationAdapter#onAnimationUpdate
final Rect startBounds = target.startBounds;
final Rect parentBounds = target.taskInfo.configuration.windowConfiguration.getBounds();
- final Rect endBounds = target.localBounds;
+ final Rect endBounds = target.screenSpaceBounds;
float scaleX = ((float) startBounds.width()) / endBounds.width();
float scaleY = ((float) startBounds.height()) / endBounds.height();
// Start leash is a child of the end leash. Reverse the scale so that the start leash won't
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index e511bffad247..3ab062499845 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -43,6 +43,7 @@ import android.util.Slog;
import android.view.Surface;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
+import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -64,7 +65,8 @@ import java.io.PrintWriter;
/**
* Manages and manipulates the one handed states, transitions, and gesture for phones.
*/
-public class OneHandedController implements RemoteCallable<OneHandedController> {
+public class OneHandedController implements RemoteCallable<OneHandedController>,
+ DisplayChangeController.OnDisplayChangingListener {
private static final String TAG = "OneHandedController";
private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
@@ -106,19 +108,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
private OneHandedBackgroundPanelOrganizer mBackgroundPanelOrganizer;
private OneHandedUiEventLogger mOneHandedUiEventLogger;
- /**
- * Handle rotation based on OnDisplayChangingListener callback
- */
- private final DisplayChangeController.OnDisplayChangingListener mRotationController =
- (display, fromRotation, toRotation, wct) -> {
- if (!isInitialized()) {
- return;
- }
- mDisplayAreaOrganizer.onRotateDisplay(mContext, toRotation, wct);
- mOneHandedUiEventLogger.writeEvent(
- OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_ROTATION_OUT);
- };
-
private final DisplayController.OnDisplaysChangedListener mDisplaysChangedListener =
new DisplayController.OnDisplaysChangedListener() {
@Override
@@ -296,7 +285,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
getObserver(this::onSwipeToNotificationEnabledChanged);
mShortcutEnabledObserver = getObserver(this::onShortcutEnabledChanged);
- mDisplayController.addDisplayChangingController(mRotationController);
+ mDisplayController.addDisplayChangingController(this);
setupCallback();
registerSettingObservers(mUserId);
setupTimeoutListener();
@@ -745,6 +734,27 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
}
/**
+ * Handles rotation based on OnDisplayChangingListener callback
+ */
+ @Override
+ public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
+ WindowContainerTransaction wct) {
+ if (!isInitialized()) {
+ return;
+ }
+
+ if (!mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(mContext.getContentResolver(),
+ mUserId) || mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
+ mContext.getContentResolver(), mUserId)) {
+ return;
+ }
+
+ mDisplayAreaOrganizer.onRotateDisplay(mContext, toRotation, wct);
+ mOneHandedUiEventLogger.writeEvent(
+ OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_ROTATION_OUT);
+ }
+
+ /**
* The interface for calls from outside the Shell, within the host process.
*/
@ExternalThread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index c2bbd9e99bac..1b2f4768110b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -16,8 +16,6 @@
package com.android.wm.shell.onehanded;
-import static android.os.UserHandle.myUserId;
-
import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_EXIT;
import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_TRIGGER;
@@ -186,20 +184,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
if (mDisplayLayout.rotation() == toRotation) {
return;
}
-
- if (!mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(context.getContentResolver(),
- myUserId())) {
- return;
- }
-
mDisplayLayout.rotateTo(context.getResources(), toRotation);
updateDisplayBounds();
-
- if (mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
- context.getContentResolver(), myUserId())) {
- // If current settings is swipe notification, skip finishOffset.
- return;
- }
finishOffset(0, TRANSITION_DIRECTION_EXIT);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 911fe0753845..0a3a84923053 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -42,6 +42,7 @@ import android.util.ArrayMap;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
@@ -332,6 +333,58 @@ public class OneHandedControllerTest extends OneHandedTestCase {
}
@Test
+ public void testOneHandedEnabledRotation90ShouldHandleRotate() {
+ when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(true);
+ when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
+ false);
+ final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
+ mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
+ Surface.ROTATION_90, handlerWCT);
+
+ verify(mMockDisplayAreaOrganizer, atLeastOnce()).onRotateDisplay(eq(mContext),
+ eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
+ }
+
+ @Test
+ public void testOneHandedDisabledRotation90ShouldNotHandleRotate() {
+ when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(false);
+ when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
+ false);
+ final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
+ mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
+ Surface.ROTATION_90, handlerWCT);
+
+ verify(mMockDisplayAreaOrganizer, never()).onRotateDisplay(eq(mContext),
+ eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
+ }
+
+ @Test
+ public void testSwipeToNotificationEnabledRotation90ShouldNotHandleRotate() {
+ when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(true);
+ when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
+ true);
+ final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
+ mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
+ Surface.ROTATION_90, handlerWCT);
+
+ verify(mMockDisplayAreaOrganizer, never()).onRotateDisplay(eq(mContext),
+ eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
+ }
+
+ @Test
+ public void testSwipeToNotificationDisabledRotation90ShouldHandleRotate() {
+ when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn(true);
+ when(mMockSettingsUitl.getSettingsSwipeToNotificationEnabled(any(), anyInt())).thenReturn(
+ false);
+ final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
+ mSpiedOneHandedController.onRotateDisplay(mDisplay.getDisplayId(), Surface.ROTATION_0,
+ Surface.ROTATION_90, handlerWCT);
+
+ verify(mMockDisplayAreaOrganizer, atLeastOnce()).onRotateDisplay(eq(mContext),
+ eq(Surface.ROTATION_90), any(WindowContainerTransaction.class));
+ }
+
+ @Test
public void testStateActive_shortcutRequestActivate_skipActions() {
when(mSpiedTransitionState.getState()).thenReturn(STATE_ACTIVE);
when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 2c81c971f7a6..48145d2331ee 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -243,13 +243,12 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
// the corresponding SkImageFilter each time.
// See b/193145089 and b/197263715
if (!Properties::enableRenderEffectCache) {
+ snapshotImage = renderNode->getLayerSurface()->makeImageSnapshot();
if (imageFilter) {
auto subset = SkIRect::MakeWH(srcBounds.width(), srcBounds.height());
snapshotImage = snapshotImage->makeWithFilter(recordingContext, imageFilter,
subset, clipBounds.roundOut(),
&srcBounds, &offset);
- } else {
- snapshotImage = renderNode->getLayerSurface()->makeImageSnapshot();
}
} else {
const auto snapshotResult = renderNode->updateSnapshotIfRequired(
diff --git a/packages/PrintSpooler/res/values-te/strings.xml b/packages/PrintSpooler/res/values-te/strings.xml
index cf0e0f6b506e..50e6f3b7dac5 100644
--- a/packages/PrintSpooler/res/values-te/strings.xml
+++ b/packages/PrintSpooler/res/values-te/strings.xml
@@ -50,8 +50,8 @@
<string name="search" msgid="5421724265322228497">"సెర్చ్"</string>
<string name="all_printers_label" msgid="3178848870161526399">"అన్ని ప్రింటర్‌లు"</string>
<string name="add_print_service_label" msgid="5356702546188981940">"సేవను జోడించు"</string>
- <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"శోధన పెట్టె చూపబడింది"</string>
- <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"శోధన పెట్టె దాచబడింది"</string>
+ <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"సెర్చ్ బాక్స్ చూపబడింది"</string>
+ <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"సెర్చ్ బాక్స్ దాచబడింది"</string>
<string name="print_add_printer" msgid="1088656468360653455">"ప్రింటర్‌ను జోడించు"</string>
<string name="print_select_printer" msgid="7388760939873368698">"ప్రింటర్‌ను ఎంచుకోండి"</string>
<string name="print_forget_printer" msgid="5035287497291910766">"ప్రింటర్‌ను విస్మరించు"</string>
diff --git a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
index 8216edf872f3..fe7988f7e500 100644
--- a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
@@ -43,6 +43,7 @@ public class FooterPreference extends Preference {
View.OnClickListener mLearnMoreListener;
private CharSequence mContentDescription;
private CharSequence mLearnMoreContentDescription;
+ private FooterLearnMoreSpan mLearnMoreSpan;
public FooterPreference(Context context, AttributeSet attrs) {
super(context, attrs, R.attr.footerPreferenceStyle);
@@ -68,7 +69,11 @@ public class FooterPreference extends Preference {
if (learnMore != null && mLearnMoreListener != null) {
learnMore.setVisibility(View.VISIBLE);
SpannableString learnMoreText = new SpannableString(learnMore.getText());
- learnMoreText.setSpan(new FooterLearnMoreSpan(mLearnMoreListener), 0,
+ if (mLearnMoreSpan != null) {
+ learnMoreText.removeSpan(mLearnMoreSpan);
+ }
+ mLearnMoreSpan = new FooterLearnMoreSpan(mLearnMoreListener);
+ learnMoreText.setSpan(mLearnMoreSpan, 0,
learnMoreText.length(), 0);
learnMore.setText(learnMoreText);
if (!TextUtils.isEmpty(mLearnMoreContentDescription)) {
diff --git a/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
index 54145d60fb32..eecb4bff16ae 100644
--- a/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
@@ -34,17 +34,21 @@
android:orientation="vertical">
<ImageView
+ android:id="@+id/background_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:scaleType="centerInside"
+ android:layout_gravity="center"
+ android:adjustViewBounds="true"
android:src="@drawable/protection_background"/>
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_view"
- android:adjustViewBounds="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center" />
+ android:layout_gravity="center"
+ android:maxWidth="@dimen/settingslib_illustration_width"
+ android:maxHeight="@dimen/settingslib_illustration_height"
+ android:adjustViewBounds="true"/>
<FrameLayout
android:id="@+id/middleground_layout"
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
index 1f80a3e04093..468a97630e19 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -17,6 +17,7 @@
package com.android.settingslib.widget;
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Animatable2;
@@ -50,7 +51,9 @@ public class IllustrationPreference extends Preference {
private static final String TAG = "IllustrationPreference";
private static final boolean IS_ENABLED_LOTTIE_ADAPTIVE_COLOR = false;
+ private static final int SIZE_UNSPECIFIED = -1;
+ private int mMaxHeight = SIZE_UNSPECIFIED;
private int mImageResId;
private boolean mIsAutoScale;
private Uri mImageUri;
@@ -98,6 +101,8 @@ public class IllustrationPreference extends Preference {
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
+ final ImageView backgroundView =
+ (ImageView) holder.findViewById(R.id.background_view);
final FrameLayout middleGroundLayout =
(FrameLayout) holder.findViewById(R.id.middleground_layout);
final LottieAnimationView illustrationView =
@@ -115,6 +120,7 @@ public class IllustrationPreference extends Preference {
illustrationFrame.setLayoutParams(lp);
handleImageWithAnimation(illustrationView);
+ handleImageFrameMaxHeight(backgroundView, illustrationView);
if (mIsAutoScale) {
illustrationView.setScaleType(mIsAutoScale
@@ -220,6 +226,19 @@ public class IllustrationPreference extends Preference {
return mImageUri;
}
+ /**
+ * Sets the maximum height of the views, still use the specific one if the maximum height was
+ * larger than the specific height from XML.
+ *
+ * @param maxHeight the maximum height of the frame views in terms of pixels.
+ */
+ public void setMaxHeight(int maxHeight) {
+ if (maxHeight != mMaxHeight) {
+ mMaxHeight = maxHeight;
+ notifyChanged();
+ }
+ }
+
private void resetImageResourceCache() {
mImageDrawable = null;
mImageUri = null;
@@ -274,6 +293,23 @@ public class IllustrationPreference extends Preference {
}
}
+ private void handleImageFrameMaxHeight(ImageView backgroundView, ImageView illustrationView) {
+ if (mMaxHeight == SIZE_UNSPECIFIED) {
+ return;
+ }
+
+ final Resources res = backgroundView.getResources();
+ final int frameWidth = res.getDimensionPixelSize(R.dimen.settingslib_illustration_width);
+ final int frameHeight = res.getDimensionPixelSize(R.dimen.settingslib_illustration_height);
+ final int restrictedMaxHeight = Math.min(mMaxHeight, frameHeight);
+ backgroundView.setMaxHeight(restrictedMaxHeight);
+ illustrationView.setMaxHeight(restrictedMaxHeight);
+
+ // Ensures the illustration view size is smaller than or equal to the background view size.
+ final float aspectRatio = (float) frameWidth / frameHeight;
+ illustrationView.setMaxWidth((int) (restrictedMaxHeight * aspectRatio));
+ }
+
private void startAnimation(Drawable drawable) {
if (!(drawable instanceof Animatable)) {
return;
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java b/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
index a0c8663a8271..ea5105bd9e0d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
@@ -319,23 +319,11 @@ public class SettingsInjector {
@Override
public boolean onPreferenceClick(Preference preference) {
- // Activity to start if they click on the preference. Must start in new task to ensure
- // that "android.settings.LOCATION_SOURCE_SETTINGS" brings user back to
- // Settings > Location.
+ // Activity to start if they click on the preference.
Intent settingIntent = new Intent();
settingIntent.setClassName(mInfo.packageName, mInfo.settingsActivity);
+ // No flags set to ensure the activity is launched within the same settings task.
logPreferenceClick(settingIntent);
- // Sometimes the user may navigate back to "Settings" and launch another different
- // injected setting after one injected setting has been launched.
- //
- // FLAG_ACTIVITY_CLEAR_TOP allows multiple Activities to stack on each other. When
- // "back" button is clicked, the user will navigate through all the injected settings
- // launched before. Such behavior could be quite confusing sometimes.
- //
- // In order to avoid such confusion, we use FLAG_ACTIVITY_CLEAR_TASK, which always clear
- // up all existing injected settings and make sure that "back" button always brings the
- // user back to "Settings" directly.
- settingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
mContext.startActivityAsUser(settingIntent, mInfo.mUserHandle);
return true;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
index 9e3312ae2ddf..29549d9a7fa7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
@@ -55,6 +55,7 @@ public class IllustrationPreferenceTest {
@Mock
private ViewGroup mRootView;
private Uri mImageUri;
+ private ImageView mBackgroundView;
private LottieAnimationView mAnimationView;
private IllustrationPreference mPreference;
private PreferenceViewHolder mViewHolder;
@@ -66,6 +67,7 @@ public class IllustrationPreferenceTest {
MockitoAnnotations.initMocks(this);
mImageUri = new Uri.Builder().build();
+ mBackgroundView = new ImageView(mContext);
mAnimationView = spy(new LottieAnimationView(mContext));
mMiddleGroundLayout = new FrameLayout(mContext);
final FrameLayout illustrationFrame = new FrameLayout(mContext);
@@ -73,6 +75,7 @@ public class IllustrationPreferenceTest {
new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
doReturn(mMiddleGroundLayout).when(mRootView).findViewById(R.id.middleground_layout);
+ doReturn(mBackgroundView).when(mRootView).findViewById(R.id.background_view);
doReturn(mAnimationView).when(mRootView).findViewById(R.id.lottie_view);
doReturn(illustrationFrame).when(mRootView).findViewById(R.id.illustration_frame);
mViewHolder = spy(PreferenceViewHolder.createInstanceForTests(mRootView));
@@ -155,4 +158,32 @@ public class IllustrationPreferenceTest {
verify(mAnimationView).setFailureListener(any());
}
+
+ @Test
+ public void setMaxHeight_smallerThanRestrictedHeight_matchResult() {
+ final int restrictedHeight =
+ mContext.getResources().getDimensionPixelSize(
+ R.dimen.settingslib_illustration_height);
+ final int maxHeight = restrictedHeight - 200;
+
+ mPreference.setMaxHeight(maxHeight);
+ mPreference.onBindViewHolder(mViewHolder);
+
+ assertThat(mBackgroundView.getMaxHeight()).isEqualTo(maxHeight);
+ assertThat(mAnimationView.getMaxHeight()).isEqualTo(maxHeight);
+ }
+
+ @Test
+ public void setMaxHeight_largerThanRestrictedHeight_specificHeight() {
+ final int restrictedHeight =
+ mContext.getResources().getDimensionPixelSize(
+ R.dimen.settingslib_illustration_height);
+ final int maxHeight = restrictedHeight + 200;
+
+ mPreference.setMaxHeight(maxHeight);
+ mPreference.onBindViewHolder(mViewHolder);
+
+ assertThat(mBackgroundView.getMaxHeight()).isEqualTo(restrictedHeight);
+ assertThat(mAnimationView.getMaxHeight()).isEqualTo(restrictedHeight);
+ }
}
diff --git a/packages/SystemUI/animation/res/anim/launch_host_dialog_enter.xml b/packages/SystemUI/animation/res/anim/launch_host_dialog_enter.xml
new file mode 100644
index 000000000000..c6b87d38f7da
--- /dev/null
+++ b/packages/SystemUI/animation/res/anim/launch_host_dialog_enter.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<!-- The enter animation of the host dialog is a translation of 0px that lasts 500ms so that the -->
+<!-- host dialog is directly visible but the dim background still takes 500ms to fade in. -->
+<translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromXDelta="0"
+ android:toXDelta="0"
+ android:duration="500" /> \ No newline at end of file
diff --git a/packages/SystemUI/animation/res/anim/launch_host_dialog_exit.xml b/packages/SystemUI/animation/res/anim/launch_host_dialog_exit.xml
new file mode 100644
index 000000000000..a0f441eaeed4
--- /dev/null
+++ b/packages/SystemUI/animation/res/anim/launch_host_dialog_exit.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+<alpha
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:interpolator/decelerate_cubic"
+ android:duration="150"
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0" /> \ No newline at end of file
diff --git a/packages/SystemUI/animation/res/values/ids.xml b/packages/SystemUI/animation/res/values/ids.xml
new file mode 100644
index 000000000000..ef60a248f79a
--- /dev/null
+++ b/packages/SystemUI/animation/res/values/ids.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<resources>
+ <item type="id" name="launch_animation_running"/>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/animation/res/values/styles.xml b/packages/SystemUI/animation/res/values/styles.xml
new file mode 100644
index 000000000000..ad06c9192bc3
--- /dev/null
+++ b/packages/SystemUI/animation/res/values/styles.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<resources>
+ <style name="HostDialogTheme">
+ <item name="android:windowAnimationStyle">@style/Animation.HostDialog</item>
+ <item name="android:windowIsFloating">false</item>
+ <item name="android:backgroundDimEnabled">true</item>
+ <item name="android:navigationBarColor">@android:color/transparent</item>
+ </style>
+
+ <style name="Animation.HostDialog" parent="@android:style/Animation">
+ <item name="android:windowEnterAnimation">@anim/launch_host_dialog_enter</item>
+ <item name="android:windowExitAnimation">@anim/launch_host_dialog_exit</item>
+ </style>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 9c1e12923b43..702060338359 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -1,23 +1,31 @@
+/*
+ * 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.animation
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.animation.ValueAnimator
import android.app.ActivityManager
import android.app.ActivityTaskManager
import android.app.PendingIntent
import android.app.TaskInfo
-import android.content.Context
import android.graphics.Matrix
-import android.graphics.PorterDuff
-import android.graphics.PorterDuffXfermode
import android.graphics.Rect
import android.graphics.RectF
-import android.graphics.drawable.GradientDrawable
import android.os.Looper
import android.os.RemoteException
import android.util.Log
-import android.util.MathUtils
import android.view.IRemoteAnimationFinishedCallback
import android.view.IRemoteAnimationRunner
import android.view.RemoteAnimationAdapter
@@ -26,7 +34,6 @@ import android.view.SyncRtSurfaceTransactionApplier
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
-import android.view.animation.AnimationUtils
import android.view.animation.PathInterpolator
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.policy.ScreenDecorationsUtils
@@ -38,52 +45,23 @@ private const val TAG = "ActivityLaunchAnimator"
* A class that allows activities to be started in a seamless way from a view that is transforming
* nicely into the starting window.
*/
-class ActivityLaunchAnimator(
- private val callback: Callback,
- context: Context
-) {
+class ActivityLaunchAnimator(private val launchAnimator: LaunchAnimator) {
companion object {
- private const val DEBUG = false
- const val ANIMATION_DURATION = 500L
- private const val ANIMATION_DURATION_FADE_OUT_CONTENT = 150L
- private const val ANIMATION_DURATION_FADE_IN_WINDOW = 183L
- private const val ANIMATION_DELAY_FADE_IN_WINDOW = ANIMATION_DURATION_FADE_OUT_CONTENT
private const val ANIMATION_DURATION_NAV_FADE_IN = 266L
private const val ANIMATION_DURATION_NAV_FADE_OUT = 133L
private const val ANIMATION_DELAY_NAV_FADE_IN =
- ANIMATION_DURATION - ANIMATION_DURATION_NAV_FADE_IN
+ LaunchAnimator.ANIMATION_DURATION - ANIMATION_DURATION_NAV_FADE_IN
private const val LAUNCH_TIMEOUT = 1000L
- @JvmField val CONTENT_FADE_OUT_INTERPOLATOR = PathInterpolator(0f, 0f, 0.2f, 1f)
- private val WINDOW_FADE_IN_INTERPOLATOR = PathInterpolator(0f, 0f, 0.6f, 1f)
private val NAV_FADE_IN_INTERPOLATOR = PathInterpolator(0f, 0f, 0f, 1f)
private val NAV_FADE_OUT_INTERPOLATOR = PathInterpolator(0.2f, 0f, 1f, 1f)
-
- private val SRC_MODE = PorterDuffXfermode(PorterDuff.Mode.SRC)
-
- /**
- * Given the [linearProgress] of a launch animation, return the linear progress of the
- * sub-animation starting [delay] ms after the launch animation and that lasts [duration].
- */
- @JvmStatic
- fun getProgress(linearProgress: Float, delay: Long, duration: Long): Float {
- return MathUtils.constrain(
- (linearProgress * ANIMATION_DURATION - delay) / duration,
- 0.0f,
- 1.0f
- )
- }
}
- /** The interpolator used for the width, height, Y position and corner radius. */
- private val animationInterpolator = AnimationUtils.loadInterpolator(context,
- R.interpolator.launch_animation_interpolator_y)
-
- /** The interpolator used for the X position. */
- private val animationInterpolatorX = AnimationUtils.loadInterpolator(context,
- R.interpolator.launch_animation_interpolator_x)
-
- private val cornerRadii = FloatArray(8)
+ /**
+ * The callback of this animator. This should be set before any call to
+ * [start(Pending)IntentWithAnimation].
+ */
+ var callback: Callback? = null
/**
* Start an intent and animate the opening window. The intent will be started by running
@@ -119,6 +97,8 @@ class ActivityLaunchAnimator(
return
}
+ val callback = this.callback ?: throw IllegalStateException(
+ "ActivityLaunchAnimator.callback must be set before using this animator")
val runner = Runner(controller)
val hideKeyguardWithAnimation = callback.isOnKeyguard() && !showOverLockscreen
@@ -126,9 +106,9 @@ class ActivityLaunchAnimator(
// keyguard with the animation
val animationAdapter = if (!hideKeyguardWithAnimation) {
RemoteAnimationAdapter(
- runner,
- ANIMATION_DURATION,
- ANIMATION_DURATION - 150 /* statusBarTransitionDelay */
+ runner,
+ LaunchAnimator.ANIMATION_DURATION,
+ LaunchAnimator.ANIMATION_DURATION - 150 /* statusBarTransitionDelay */
)
} else {
null
@@ -150,10 +130,10 @@ class ActivityLaunchAnimator(
// Only animate if the app is not already on top and will be opened, unless we are on the
// keyguard.
val willAnimate =
- launchResult == ActivityManager.START_TASK_TO_FRONT ||
- launchResult == ActivityManager.START_SUCCESS ||
- (launchResult == ActivityManager.START_DELIVERED_TO_TOP &&
- hideKeyguardWithAnimation)
+ launchResult == ActivityManager.START_TASK_TO_FRONT ||
+ launchResult == ActivityManager.START_SUCCESS ||
+ (launchResult == ActivityManager.START_DELIVERED_TO_TOP &&
+ hideKeyguardWithAnimation)
Log.i(TAG, "launchResult=$launchResult willAnimate=$willAnimate " +
"hideKeyguardWithAnimation=$hideKeyguardWithAnimation")
@@ -234,7 +214,7 @@ class ActivityLaunchAnimator(
*
* Note that all callbacks (onXXX methods) are all called on the main thread.
*/
- interface Controller {
+ interface Controller : LaunchAnimator.Controller {
companion object {
/**
* Return a [Controller] that will animate and expand [view] into the opening window.
@@ -259,53 +239,12 @@ class ActivityLaunchAnimator(
}
/**
- * The container in which the view that started the intent will be animating together with
- * the opening window.
- *
- * This will be used to:
- * - Get the associated [Context].
- * - Compute whether we are expanding fully above the current window.
- * - Apply surface transactions in sync with RenderThread.
- *
- * This container can be changed to force this [Controller] to animate the expanding view
- * inside a different location, for instance to ensure correct layering during the
- * animation.
- */
- var launchContainer: ViewGroup
-
- /**
- * Return the [State] of the view that will be animated. We will animate from this state to
- * the final window state.
- *
- * Note: This state will be mutated and passed to [onLaunchAnimationProgress] during the
- * animation.
- */
- fun createAnimatorState(): State
-
- /**
* The intent was started. If [willAnimate] is false, nothing else will happen and the
* animation will not be started.
*/
fun onIntentStarted(willAnimate: Boolean) {}
/**
- * The animation started. This is typically used to initialize any additional resource
- * needed for the animation. [isExpandingFullyAbove] will be true if the window is expanding
- * fully above the [root view][getRootView].
- */
- fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {}
-
- /** The animation made progress and the expandable view [state] should be updated. */
- fun onLaunchAnimationProgress(state: State, progress: Float, linearProgress: Float) {}
-
- /**
- * The animation ended. This will be called *if and only if* [onLaunchAnimationStart] was
- * called previously. This is typically used to clean up the resources initialized when the
- * animation was started.
- */
- fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {}
-
- /**
* The animation was cancelled. Note that [onLaunchAnimationEnd] will still be called after
* this if the animation was already started, i.e. if [onLaunchAnimationStart] was called
* before the cancellation.
@@ -313,66 +252,11 @@ class ActivityLaunchAnimator(
fun onLaunchAnimationCancelled() {}
}
- /** The state of an expandable view during an [ActivityLaunchAnimator] animation. */
- open class State(
- /** The position of the view in screen space coordinates. */
- var top: Int,
- var bottom: Int,
- var left: Int,
- var right: Int,
-
- var topCornerRadius: Float = 0f,
- var bottomCornerRadius: Float = 0f
- ) {
- private val startTop = top
- private val startBottom = bottom
- private val startLeft = left
- private val startRight = right
- private val startWidth = width
- private val startHeight = height
- val startCenterX = centerX
- val startCenterY = centerY
-
- val width: Int
- get() = right - left
-
- val height: Int
- get() = bottom - top
-
- open val topChange: Int
- get() = top - startTop
-
- open val bottomChange: Int
- get() = bottom - startBottom
-
- val leftChange: Int
- get() = left - startLeft
-
- val rightChange: Int
- get() = right - startRight
-
- val widthRatio: Float
- get() = width.toFloat() / startWidth
-
- val heightRatio: Float
- get() = height.toFloat() / startHeight
-
- val centerX: Float
- get() = left + width / 2f
-
- val centerY: Float
- get() = top + height / 2f
-
- /** Whether the expanded view should be visible or hidden. */
- var visible: Boolean = true
- }
-
@VisibleForTesting
inner class Runner(private val controller: Controller) : IRemoteAnimationRunner.Stub() {
private val launchContainer = controller.launchContainer
private val context = launchContainer.context
private val transactionApplier = SyncRtSurfaceTransactionApplier(launchContainer)
- private var animator: ValueAnimator? = null
private val matrix = Matrix()
private val invertMatrix = Matrix()
@@ -380,6 +264,7 @@ class ActivityLaunchAnimator(
private var windowCropF = RectF()
private var timedOut = false
private var cancelled = false
+ private var animation: LaunchAnimator.Animation? = null
// A timeout to cancel the remote animation if it is not started within X milliseconds after
// the intent was started.
@@ -429,7 +314,7 @@ class ActivityLaunchAnimator(
nonApps: Array<out RemoteAnimationTarget>?,
iCallback: IRemoteAnimationFinishedCallback?
) {
- if (DEBUG) {
+ if (LaunchAnimator.DEBUG) {
Log.d(TAG, "Remote animation started")
}
@@ -449,36 +334,20 @@ class ActivityLaunchAnimator(
it.windowType == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
}
- // Start state.
- val state = controller.createAnimatorState()
-
- val startTop = state.top
- val startBottom = state.bottom
- val startLeft = state.left
- val startRight = state.right
- val startXCenter = (startLeft + startRight) / 2f
- val startWidth = startRight - startLeft
-
- val startTopCornerRadius = state.topCornerRadius
- val startBottomCornerRadius = state.bottomCornerRadius
-
- // End state.
val windowBounds = window.screenSpaceBounds
- val endTop = windowBounds.top
- val endBottom = windowBounds.bottom
- val endLeft = windowBounds.left
- val endRight = windowBounds.right
- val endXCenter = (endLeft + endRight) / 2f
- val endWidth = endRight - endLeft
-
- // TODO(b/184121838): Ensure that we are launching on the same screen.
- val rootViewLocation = launchContainer.locationOnScreen
- val isExpandingFullyAbove = endTop <= rootViewLocation[1] &&
- endBottom >= rootViewLocation[1] + launchContainer.height &&
- endLeft <= rootViewLocation[0] &&
- endRight >= rootViewLocation[0] + launchContainer.width
-
- // TODO(b/184121838): We should somehow get the top and bottom radius of the window.
+ val endState = LaunchAnimator.State(
+ top = windowBounds.top,
+ bottom = windowBounds.bottom,
+ left = windowBounds.left,
+ right = windowBounds.right
+ )
+ val callback = this@ActivityLaunchAnimator.callback!!
+ val windowBackgroundColor = callback.getBackgroundColor(window.taskInfo)
+
+ // TODO(b/184121838): We should somehow get the top and bottom radius of the window
+ // instead of recomputing isExpandingFullyAbove here.
+ val isExpandingFullyAbove =
+ launchAnimator.isExpandingFullyAbove(controller.launchContainer, endState)
val endRadius = if (isExpandingFullyAbove) {
// Most of the time, expanding fully above the root view means expanding in full
// screen.
@@ -488,97 +357,40 @@ class ActivityLaunchAnimator(
// a radius of 0.
0f
}
+ endState.topCornerRadius = endRadius
+ endState.bottomCornerRadius = endRadius
- // We add an extra layer with the same color as the app splash screen background color,
- // which is usually the same color of the app background. We first fade in this layer
- // to hide the expanding view, then we fade it out with SRC mode to draw a hole in the
- // launch container and reveal the opening window.
- val windowBackgroundColor = callback.getBackgroundColor(window.taskInfo)
- val windowBackgroundLayer = GradientDrawable().apply {
- setColor(windowBackgroundColor)
- alpha = 0
- }
-
- // Update state.
- val animator = ValueAnimator.ofFloat(0f, 1f)
- this.animator = animator
- animator.duration = ANIMATION_DURATION
- animator.interpolator = Interpolators.LINEAR
-
- val launchContainerOverlay = launchContainer.overlay
- animator.addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationStart(animation: Animator?, isReverse: Boolean) {
- if (DEBUG) {
- Log.d(TAG, "Animation started")
- }
-
+ // We animate the opening window and delegate the view expansion to [this.controller].
+ val delegate = this.controller
+ val controller = object : LaunchAnimator.Controller by delegate {
+ override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
callback.setBlursDisabledForAppLaunch(true)
- controller.onLaunchAnimationStart(isExpandingFullyAbove)
-
- // Add the drawable to the launch container overlay. Overlays always draw
- // drawables after views, so we know that it will be drawn above any view added
- // by the controller.
- launchContainerOverlay.add(windowBackgroundLayer)
+ delegate.onLaunchAnimationStart(isExpandingFullyAbove)
}
- override fun onAnimationEnd(animation: Animator?) {
- if (DEBUG) {
- Log.d(TAG, "Animation ended")
- }
-
+ override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
callback.setBlursDisabledForAppLaunch(false)
iCallback?.invoke()
- controller.onLaunchAnimationEnd(isExpandingFullyAbove)
- launchContainerOverlay.remove(windowBackgroundLayer)
+ delegate.onLaunchAnimationEnd(isExpandingFullyAbove)
}
- })
- animator.addUpdateListener { animation ->
- if (cancelled) {
- return@addUpdateListener
+ override fun onLaunchAnimationProgress(
+ state: LaunchAnimator.State,
+ progress: Float,
+ linearProgress: Float
+ ) {
+ applyStateToWindow(window, state)
+ navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) }
+ delegate.onLaunchAnimationProgress(state, progress, linearProgress)
}
-
- val linearProgress = animation.animatedFraction
- val progress = animationInterpolator.getInterpolation(linearProgress)
- val xProgress = animationInterpolatorX.getInterpolation(linearProgress)
- val xCenter = MathUtils.lerp(startXCenter, endXCenter, xProgress)
- val halfWidth = lerp(startWidth, endWidth, progress) / 2
-
- state.top = lerp(startTop, endTop, progress).roundToInt()
- state.bottom = lerp(startBottom, endBottom, progress).roundToInt()
- state.left = (xCenter - halfWidth).roundToInt()
- state.right = (xCenter + halfWidth).roundToInt()
-
- state.topCornerRadius = MathUtils.lerp(startTopCornerRadius, endRadius, progress)
- state.bottomCornerRadius =
- MathUtils.lerp(startBottomCornerRadius, endRadius, progress)
-
- // The expanding view can/should be hidden once it is completely coverred by the
- // windowBackgroundLayer.
- state.visible =
- getProgress(linearProgress, 0, ANIMATION_DURATION_FADE_OUT_CONTENT) < 1
-
- applyStateToWindow(window, state)
- applyStateToWindowBackgroundLayer(windowBackgroundLayer, state, linearProgress)
- navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) }
-
- // If we started expanding the view, we make it 1 pixel smaller on all sides to
- // avoid artefacts on the corners caused by anti-aliasing of the view background and
- // the window background layer.
- if (state.top != startTop && state.left != startLeft &&
- state.bottom != startBottom && state.right != startRight) {
- state.top += 1
- state.left += 1
- state.right -= 1
- state.bottom -= 1
- }
- controller.onLaunchAnimationProgress(state, progress, linearProgress)
}
- animator.start()
+ // We draw a hole when the additional layer is fading out to reveal the opening window.
+ animation = launchAnimator.startAnimation(
+ controller, endState, windowBackgroundColor, drawHole = true)
}
- private fun applyStateToWindow(window: RemoteAnimationTarget, state: State) {
+ private fun applyStateToWindow(window: RemoteAnimationTarget, state: LaunchAnimator.State) {
val screenBounds = window.screenSpaceBounds
val centerX = (screenBounds.left + screenBounds.right) / 2f
val centerY = (screenBounds.top + screenBounds.bottom) / 2f
@@ -632,48 +444,13 @@ class ActivityLaunchAnimator(
transactionApplier.scheduleApply(params)
}
- private fun applyStateToWindowBackgroundLayer(
- drawable: GradientDrawable,
- state: State,
- linearProgress: Float
- ) {
- // Update position.
- drawable.setBounds(state.left, state.top, state.right, state.bottom)
-
- // Update radius.
- cornerRadii[0] = state.topCornerRadius
- cornerRadii[1] = state.topCornerRadius
- cornerRadii[2] = state.topCornerRadius
- cornerRadii[3] = state.topCornerRadius
- cornerRadii[4] = state.bottomCornerRadius
- cornerRadii[5] = state.bottomCornerRadius
- cornerRadii[6] = state.bottomCornerRadius
- cornerRadii[7] = state.bottomCornerRadius
- drawable.cornerRadii = cornerRadii
-
- // We first fade in the background layer to hide the expanding view, then fade it out
- // with SRC mode to draw a hole punch in the status bar and reveal the opening window.
- val fadeInProgress = getProgress(linearProgress, 0, ANIMATION_DURATION_FADE_OUT_CONTENT)
- if (fadeInProgress < 1) {
- val alpha = CONTENT_FADE_OUT_INTERPOLATOR.getInterpolation(fadeInProgress)
- drawable.alpha = (alpha * 0xFF).roundToInt()
- drawable.setXfermode(null)
- } else {
- val fadeOutProgress = getProgress(linearProgress,
- ANIMATION_DELAY_FADE_IN_WINDOW, ANIMATION_DURATION_FADE_IN_WINDOW)
- val alpha = 1 - WINDOW_FADE_IN_INTERPOLATOR.getInterpolation(fadeOutProgress)
- drawable.alpha = (alpha * 0xFF).roundToInt()
- drawable.setXfermode(SRC_MODE)
- }
- }
-
private fun applyStateToNavigationBar(
navigationBar: RemoteAnimationTarget,
- state: State,
+ state: LaunchAnimator.State,
linearProgress: Float
) {
- val fadeInProgress = getProgress(linearProgress, ANIMATION_DELAY_NAV_FADE_IN,
- ANIMATION_DURATION_NAV_FADE_OUT)
+ val fadeInProgress = LaunchAnimator.getProgress(linearProgress,
+ ANIMATION_DELAY_NAV_FADE_IN, ANIMATION_DURATION_NAV_FADE_OUT)
val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(navigationBar.leash)
if (fadeInProgress > 0) {
@@ -682,13 +459,13 @@ class ActivityLaunchAnimator(
0f, (state.top - navigationBar.sourceContainerBounds.top).toFloat())
windowCrop.set(state.left, 0, state.right, state.height)
params
- .withAlpha(NAV_FADE_IN_INTERPOLATOR.getInterpolation(fadeInProgress))
- .withMatrix(matrix)
- .withWindowCrop(windowCrop)
- .withVisibility(true)
+ .withAlpha(NAV_FADE_IN_INTERPOLATOR.getInterpolation(fadeInProgress))
+ .withMatrix(matrix)
+ .withWindowCrop(windowCrop)
+ .withVisibility(true)
} else {
- val fadeOutProgress = getProgress(linearProgress, 0,
- ANIMATION_DURATION_NAV_FADE_OUT)
+ val fadeOutProgress = LaunchAnimator.getProgress(linearProgress, 0,
+ ANIMATION_DURATION_NAV_FADE_OUT)
params.withAlpha(1f - NAV_FADE_OUT_INTERPOLATOR.getInterpolation(fadeOutProgress))
}
@@ -714,7 +491,7 @@ class ActivityLaunchAnimator(
cancelled = true
removeTimeout()
context.mainExecutor.execute {
- animator?.cancel()
+ animation?.cancel()
controller.onLaunchAnimationCancelled()
}
}
@@ -726,9 +503,5 @@ class ActivityLaunchAnimator(
e.printStackTrace()
}
}
-
- private fun lerp(start: Int, stop: Int, amount: Float): Float {
- return MathUtils.lerp(start.toFloat(), stop.toFloat(), amount)
- }
}
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt
index d4be25382395..258ca6bdf79b 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.animation
/**
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
new file mode 100644
index 000000000000..c2b36089d0a7
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -0,0 +1,541 @@
+/*
+ * 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.animation
+
+import android.app.Dialog
+import android.content.Context
+import android.graphics.Color
+import android.os.Looper
+import android.util.Log
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewTreeObserver
+import android.view.WindowManager
+import android.widget.FrameLayout
+
+private const val TAG = "DialogLaunchAnimator"
+
+/**
+ * A class that allows dialogs to be started in a seamless way from a view that is transforming
+ * nicely into the starting dialog.
+ *
+ * Important: Don't forget to call [DialogLaunchAnimator.onDozeAmountChanged] when the doze amount
+ * changes to gracefully handle dialogs fading out when the device is dozing.
+ */
+class DialogLaunchAnimator(
+ private val context: Context,
+ private val launchAnimator: LaunchAnimator,
+ private val hostDialogProvider: HostDialogProvider
+) {
+ private companion object {
+ private val TAG_LAUNCH_ANIMATION_RUNNING = R.id.launch_animation_running
+ }
+
+ // TODO(b/201264644): Remove this set.
+ private val currentAnimations = hashSetOf<DialogLaunchAnimation>()
+
+ /**
+ * Show [dialog] by expanding it from [view].
+ *
+ * Caveats: When calling this function, the dialog content view will actually be stolen and
+ * attached to a different dialog (and thus a different window) which means that the actual
+ * dialog window will never be drawn. Moreover, unless [dialog] is a [ListenableDialog], you
+ * must call dismiss(), hide() and show() on the [Dialog] returned by this function to actually
+ * dismiss, hide or show the dialog.
+ */
+ fun showFromView(dialog: Dialog, view: View): Dialog {
+ if (Looper.myLooper() != Looper.getMainLooper()) {
+ throw IllegalStateException(
+ "showFromView must be called from the main thread and dialog must be created in " +
+ "the main thread")
+ }
+
+ // Make sure we don't run the launch animation from the same view twice at the same time.
+ if (view.getTag(TAG_LAUNCH_ANIMATION_RUNNING) != null) {
+ Log.e(TAG, "Not running dialog launch animation as there is already one running")
+ dialog.show()
+ return dialog
+ }
+
+ view.setTag(TAG_LAUNCH_ANIMATION_RUNNING, true)
+
+ val launchAnimation = DialogLaunchAnimation(
+ context, launchAnimator, hostDialogProvider, view,
+ onDialogDismissed = { currentAnimations.remove(it) }, originalDialog = dialog)
+ val hostDialog = launchAnimation.hostDialog
+ currentAnimations.add(launchAnimation)
+
+ // If the dialog is dismissed/hidden/shown, then we should actually dismiss/hide/show the
+ // host dialog.
+ if (dialog is ListenableDialog) {
+ dialog.addListener(object : DialogListener {
+ override fun onDismiss() {
+ dialog.removeListener(this)
+ hostDialog.dismiss()
+ }
+
+ override fun onHide() {
+ if (launchAnimation.ignoreNextCallToHide) {
+ launchAnimation.ignoreNextCallToHide = false
+ return
+ }
+
+ hostDialog.hide()
+ }
+
+ override fun onShow() {
+ hostDialog.show()
+
+ // We don't actually want to show the original dialog, so hide it.
+ launchAnimation.ignoreNextCallToHide = true
+ dialog.hide()
+ }
+ })
+ }
+
+ launchAnimation.start()
+ return hostDialog
+ }
+
+ /** Notify the current doze amount, to ensure that dialogs fade out when dozing. */
+ // TODO(b/193634619): Replace this by some mandatory constructor parameter to make sure that we
+ // don't forget to call this when the doze amount changes.
+ fun onDozeAmountChanged(amount: Float) {
+ currentAnimations.forEach { it.onDozeAmountChanged(amount) }
+ }
+
+ /**
+ * Ensure that all dialogs currently shown won't animate into their touch surface when
+ * dismissed.
+ *
+ * This is a temporary API meant to be called right before we both dismiss a dialog and start
+ * an activity, which currently does not look good if we animate the dialog into the touch
+ * surface at the same time as the activity starts.
+ *
+ * TODO(b/193634619): Remove this function and animate dialog into opening activity instead.
+ */
+ fun disableAllCurrentDialogsExitAnimations() {
+ currentAnimations.forEach { it.exitAnimationDisabled = true }
+ }
+}
+
+interface HostDialogProvider {
+ /**
+ * Create a host dialog that will be used to host a launch animation. This host dialog must:
+ * 1. call [onCreateCallback] in its onCreate() method, e.g. right after calling
+ * super.onCreate().
+ * 2. call [dismissOverride] instead of doing any dismissing logic. The actual dismissing
+ * logic should instead be done inside the lambda passed to [dismissOverride], which will
+ * be called after the exit animation.
+ *
+ * See SystemUIHostDialogProvider for an example of implementation.
+ */
+ fun createHostDialog(
+ context: Context,
+ theme: Int,
+ onCreateCallback: () -> Unit,
+ dismissOverride: (() -> Unit) -> Unit
+ ): Dialog
+}
+
+/** A dialog to/from which we can add/remove listeners. */
+interface ListenableDialog {
+ /** Add [listener] to the listeners. */
+ fun addListener(listener: DialogListener)
+
+ /** Remove [listener] from the listeners. */
+ fun removeListener(listener: DialogListener)
+}
+
+interface DialogListener {
+ /** Called when this dialog dismiss() is called. */
+ fun onDismiss()
+
+ /** Called when this dialog hide() is called. */
+ fun onHide()
+
+ /** Called when this dialog show() is called. */
+ fun onShow()
+}
+
+private class DialogLaunchAnimation(
+ private val context: Context,
+ private val launchAnimator: LaunchAnimator,
+ hostDialogProvider: HostDialogProvider,
+
+ /** The view that triggered the dialog after being tapped. */
+ private val touchSurface: View,
+
+ /**
+ * A callback that will be called with this [DialogLaunchAnimation] after the dialog was
+ * dismissed and the exit animation is done.
+ */
+ private val onDialogDismissed: (DialogLaunchAnimation) -> Unit,
+
+ /** The original dialog whose content will be shown and animate in/out in [hostDialog]. */
+ private val originalDialog: Dialog
+) {
+ /**
+ * The fullscreen dialog to which we will add the content view [originalDialogView] of
+ * [originalDialog].
+ */
+ val hostDialog = hostDialogProvider.createHostDialog(
+ context, R.style.HostDialogTheme, this::onHostDialogCreated, this::onHostDialogDismissed)
+
+ /** The root content view of [hostDialog]. */
+ private val hostDialogRoot = FrameLayout(context)
+
+ /**
+ * The content view of [originalDialog], which will be stolen from that dialog and added to
+ * [hostDialogRoot].
+ */
+ private var originalDialogView: View? = null
+
+ /**
+ * The background color of [originalDialogView], taking into consideration the [originalDialog]
+ * window background color.
+ */
+ private var originalDialogBackgroundColor = Color.BLACK
+
+ /**
+ * Whether we are currently launching/showing the dialog by animating it from [touchSurface].
+ */
+ private var isLaunching = true
+
+ /** Whether we are currently dismissing/hiding the dialog by animating into [touchSurface]. */
+ private var isDismissing = false
+
+ private var dismissRequested = false
+ private var drawHostDialog = false
+ var ignoreNextCallToHide = false
+ var exitAnimationDisabled = false
+
+ fun start() {
+ // Show the host (fullscreen) dialog, to which we will add the stolen dialog view.
+ hostDialog.show()
+
+ // Steal the dialog view. We do that by showing it but preventing it from drawing, then
+ // hiding it as soon as its content is available.
+ stealOriginalDialogContentView(then = this::showDialogFromView)
+ }
+
+ private fun onHostDialogCreated() {
+ // Make the dialog fullscreen with a transparent background.
+ hostDialog.setContentView(
+ hostDialogRoot,
+ ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT
+ )
+ )
+
+ val window = hostDialog.window
+ ?: throw IllegalStateException("There is no window associated to the host dialog")
+ window.setBackgroundDrawableResource(android.R.color.transparent)
+ window.setLayout(
+ WindowManager.LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.MATCH_PARENT
+ )
+
+ // Prevent the host dialog from drawing until the animation starts.
+ hostDialogRoot.viewTreeObserver.addOnPreDrawListener(
+ object : ViewTreeObserver.OnPreDrawListener {
+ override fun onPreDraw(): Boolean {
+ if (drawHostDialog) {
+ hostDialogRoot.viewTreeObserver.removeOnPreDrawListener(this)
+ return true
+ }
+
+ return false
+ }
+ }
+ )
+ }
+
+ /** Get the content view of [originalDialog] and pass it to [then]. */
+ private fun stealOriginalDialogContentView(then: (View) -> Unit) {
+ // The original dialog content view will be attached to android.R.id.content when the dialog
+ // is shown, so we show the dialog and add an observer to get the view but also prevents the
+ // original dialog from being drawn.
+ val androidContent = originalDialog.findViewById<ViewGroup>(android.R.id.content)
+ ?: throw IllegalStateException("Dialog does not have any android.R.id.content view")
+
+ androidContent.viewTreeObserver.addOnPreDrawListener(
+ object : ViewTreeObserver.OnPreDrawListener {
+ override fun onPreDraw(): Boolean {
+ if (androidContent.childCount == 1) {
+ androidContent.viewTreeObserver.removeOnPreDrawListener(this)
+
+ // Hide the animated dialog. Because of the dialog listener set up
+ // earlier, this would also hide the host dialog, but in this case we
+ // need to keep the host dialog visible.
+ ignoreNextCallToHide = true
+ originalDialog.hide()
+
+ then(androidContent.getChildAt(0))
+ return false
+ }
+
+ // Never draw the original dialog content.
+ return false
+ }
+ })
+ originalDialog.show()
+ }
+
+ private fun showDialogFromView(dialogView: View) {
+ // Save the dialog view for later as we will need it for the close animation.
+ this.originalDialogView = dialogView
+
+ // Close the dialog when clicking outside of it.
+ hostDialogRoot.setOnClickListener { hostDialog.dismiss() }
+ dialogView.isClickable = true
+
+ // Set the background of the window dialog to the dialog itself.
+ // TODO(b/193634619): Support dialog windows without background.
+ // TODO(b/193634619): Support dialog whose background comes from the content view instead of
+ // the window.
+ val typedArray =
+ originalDialog.context.obtainStyledAttributes(com.android.internal.R.styleable.Window)
+ val backgroundRes =
+ typedArray.getResourceId(com.android.internal.R.styleable.Window_windowBackground, 0)
+ typedArray.recycle()
+ if (backgroundRes == 0) {
+ throw IllegalStateException("Dialogs with no backgrounds on window are not supported")
+ }
+
+ dialogView.setBackgroundResource(backgroundRes)
+ originalDialogBackgroundColor =
+ GhostedViewLaunchAnimatorController.findGradientDrawable(dialogView.background!!)
+ ?.color
+ ?.defaultColor ?: Color.BLACK
+
+ // Add the dialog view to the host (fullscreen) dialog and make it invisible to make sure
+ // it's not drawn yet.
+ (dialogView.parent as? ViewGroup)?.removeView(dialogView)
+ hostDialogRoot.addView(
+ dialogView,
+
+ // We give it the size of its original dialog window.
+ FrameLayout.LayoutParams(
+ originalDialog.window.attributes.width,
+ originalDialog.window.attributes.height,
+ Gravity.CENTER
+ )
+ )
+ dialogView.visibility = View.INVISIBLE
+
+ // Start the animation when the dialog is laid out in the center of the host dialog.
+ dialogView.addOnLayoutChangeListener(object : View.OnLayoutChangeListener {
+ override fun onLayoutChange(
+ view: View,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int,
+ oldLeft: Int,
+ oldTop: Int,
+ oldRight: Int,
+ oldBottom: Int
+ ) {
+ dialogView.removeOnLayoutChangeListener(this)
+ startAnimation(
+ isLaunching = true,
+ onLaunchAnimationStart = { drawHostDialog = true },
+ onLaunchAnimationEnd = {
+ touchSurface.setTag(R.id.launch_animation_running, null)
+
+ // We hide the touch surface when the dialog is showing. We will make this
+ // view visible again when dismissing the dialog.
+ // TODO(b/193634619): Provide an easy way for views to check if they should
+ // be hidden because of a dialog launch so that they don't override this
+ // visibility when updating/refreshing itself.
+ touchSurface.visibility = View.INVISIBLE
+
+ isLaunching = false
+
+ // dismiss was called during the animation, dismiss again now to actually
+ // dismiss.
+ if (dismissRequested) {
+ hostDialog.dismiss()
+ }
+ }
+ )
+ }
+ })
+ }
+
+ private fun onHostDialogDismissed(actualDismiss: () -> Unit) {
+ if (Looper.myLooper() != Looper.getMainLooper()) {
+ context.mainExecutor.execute { onHostDialogDismissed(actualDismiss) }
+ return
+ }
+
+ // TODO(b/193634619): Support interrupting the launch animation in the middle.
+ if (isLaunching) {
+ dismissRequested = true
+ return
+ }
+
+ if (isDismissing) {
+ return
+ }
+
+ isDismissing = true
+ hideDialogIntoView { instantDismiss: Boolean ->
+ if (instantDismiss) {
+ originalDialog.hide()
+ hostDialog.hide()
+ }
+
+ originalDialog.dismiss()
+ actualDismiss()
+ }
+ }
+
+ /**
+ * Hide the dialog into the touch surface and call [dismissDialogs] when the animation is done
+ * (passing instantDismiss=true) or if it's skipped (passing instantDismiss=false) to actually
+ * dismiss the dialogs.
+ */
+ private fun hideDialogIntoView(dismissDialogs: (Boolean) -> Unit) {
+ if (!shouldAnimateDialogIntoView()) {
+ Log.i(TAG, "Skipping animation of dialog into the touch surface")
+
+ // If the view is invisible it's probably because of us, so we make it visible again.
+ if (touchSurface.visibility == View.INVISIBLE) {
+ touchSurface.visibility = View.VISIBLE
+ }
+
+ dismissDialogs(false /* instantDismiss */)
+ onDialogDismissed(this@DialogLaunchAnimation)
+ return
+ }
+
+ startAnimation(
+ isLaunching = false,
+ onLaunchAnimationStart = {
+ // Remove the dim background as soon as we start the animation.
+ hostDialog.window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
+ },
+ onLaunchAnimationEnd = {
+ touchSurface.visibility = View.VISIBLE
+ originalDialogView!!.visibility = View.INVISIBLE
+ dismissDialogs(true /* instantDismiss */)
+ onDialogDismissed(this@DialogLaunchAnimation)
+ }
+ )
+ }
+
+ private fun startAnimation(
+ isLaunching: Boolean,
+ onLaunchAnimationStart: () -> Unit = {},
+ onLaunchAnimationEnd: () -> Unit = {}
+ ) {
+ val dialogView = this.originalDialogView!!
+
+ // Create 2 ghost controllers to animate both the dialog and the touch surface in the host
+ // dialog.
+ val startView = if (isLaunching) touchSurface else dialogView
+ val endView = if (isLaunching) dialogView else touchSurface
+ val startViewController = GhostedViewLaunchAnimatorController(startView)
+ val endViewController = GhostedViewLaunchAnimatorController(endView)
+ startViewController.launchContainer = hostDialogRoot
+ endViewController.launchContainer = hostDialogRoot
+
+ val endState = endViewController.createAnimatorState()
+ val controller = object : LaunchAnimator.Controller {
+ override var launchContainer: ViewGroup
+ get() = startViewController.launchContainer
+ set(value) {
+ startViewController.launchContainer = value
+ endViewController.launchContainer = value
+ }
+
+ override fun createAnimatorState(): LaunchAnimator.State {
+ return startViewController.createAnimatorState()
+ }
+
+ override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
+ startViewController.onLaunchAnimationStart(isExpandingFullyAbove)
+ endViewController.onLaunchAnimationStart(isExpandingFullyAbove)
+
+ onLaunchAnimationStart()
+ }
+
+ override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
+ startViewController.onLaunchAnimationEnd(isExpandingFullyAbove)
+ endViewController.onLaunchAnimationEnd(isExpandingFullyAbove)
+
+ onLaunchAnimationEnd()
+ }
+
+ override fun onLaunchAnimationProgress(
+ state: LaunchAnimator.State,
+ progress: Float,
+ linearProgress: Float
+ ) {
+ startViewController.onLaunchAnimationProgress(state, progress, linearProgress)
+
+ // The end view is visible only iff the starting view is not visible.
+ state.visible = !state.visible
+ endViewController.onLaunchAnimationProgress(state, progress, linearProgress)
+
+ // If the dialog content is complex, its dimension might change during the launch
+ // animation. The animation end position might also change during the exit
+ // animation, for instance when locking the phone when the dialog is open. Therefore
+ // we update the end state to the new position/size. Usually the dialog dimension or
+ // position will change in the early frames, so changing the end state shouldn't
+ // really be noticeable.
+ endViewController.fillGhostedViewState(endState)
+ }
+ }
+
+ launchAnimator.startAnimation(controller, endState, originalDialogBackgroundColor)
+ }
+
+ private fun shouldAnimateDialogIntoView(): Boolean {
+ if (exitAnimationDisabled) {
+ return false
+ }
+
+ // The touch surface should be invisible by now, if it's not then something else changed its
+ // visibility and we probably don't want to run the animation.
+ if (touchSurface.visibility != View.INVISIBLE) {
+ return false
+ }
+
+ // If the touch surface is not attached or one of its ancestors is not visible, then we
+ // don't run the animation either.
+ if (!touchSurface.isAttachedToWindow) {
+ return false
+ }
+
+ return (touchSurface.parent as? View)?.isShown ?: true
+ }
+
+ internal fun onDozeAmountChanged(amount: Float) {
+ val alpha = Interpolators.ALPHA_OUT.getInterpolation(1 - amount)
+ val decorView = this.hostDialog.window?.decorView ?: return
+ if (decorView.hasOverlappingRendering() && alpha > 0.0f &&
+ alpha < 1.0f && decorView.layerType != View.LAYER_TYPE_HARDWARE) {
+ decorView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
+ }
+ decorView.alpha = alpha
+ }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
index b4ffb3f6cf4e..f7e0d588407f 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
@@ -1,7 +1,24 @@
+/*
+ * 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.animation
import android.graphics.Canvas
import android.graphics.ColorFilter
+import android.graphics.Insets
import android.graphics.Matrix
import android.graphics.PixelFormat
import android.graphics.Rect
@@ -42,6 +59,7 @@ open class GhostedViewLaunchAnimatorController(
override var launchContainer = ghostedView.rootView as ViewGroup
private val launchContainerOverlay: ViewGroupOverlay
get() = launchContainer.overlay
+ private val launchContainerLocation = IntArray(2)
/** The ghost view that is drawn and animated instead of the ghosted view. */
private var ghostView: GhostView? = null
@@ -59,8 +77,12 @@ open class GhostedViewLaunchAnimatorController(
* [backgroundView].
*/
private var backgroundDrawable: WrappedDrawable? = null
+ private val backgroundInsets by lazy { getBackground()?.opticalInsets ?: Insets.NONE }
private var startBackgroundAlpha: Int = 0xFF
+ private val ghostedViewLocation = IntArray(2)
+ private val ghostedViewState = LaunchAnimator.State()
+
/**
* Return the background of the [ghostedView]. This background will be used to draw the
* background of the background view that is expanding up to the final animation position. This
@@ -103,16 +125,24 @@ open class GhostedViewLaunchAnimatorController(
return gradient.cornerRadii?.get(CORNER_RADIUS_BOTTOM_INDEX) ?: gradient.cornerRadius
}
- override fun createAnimatorState(): ActivityLaunchAnimator.State {
- val location = ghostedView.locationOnScreen
- return ActivityLaunchAnimator.State(
- top = location[1],
- bottom = location[1] + ghostedView.height,
- left = location[0],
- right = location[0] + ghostedView.width,
+ override fun createAnimatorState(): LaunchAnimator.State {
+ val state = LaunchAnimator.State(
topCornerRadius = getCurrentTopCornerRadius(),
bottomCornerRadius = getCurrentBottomCornerRadius()
)
+ fillGhostedViewState(state)
+ return state
+ }
+
+ fun fillGhostedViewState(state: LaunchAnimator.State) {
+ // For the animation we are interested in the area that has a non transparent background,
+ // so we have to take the optical insets into account.
+ ghostedView.getLocationOnScreen(ghostedViewLocation)
+ val insets = backgroundInsets
+ state.top = ghostedViewLocation[1] + insets.top
+ state.bottom = ghostedViewLocation[1] + ghostedView.height - insets.bottom
+ state.left = ghostedViewLocation[0] + insets.left
+ state.right = ghostedViewLocation[0] + ghostedView.width - insets.right
}
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -144,7 +174,7 @@ open class GhostedViewLaunchAnimatorController(
}
override fun onLaunchAnimationProgress(
- state: ActivityLaunchAnimator.State,
+ state: LaunchAnimator.State,
progress: Float,
linearProgress: Float
) {
@@ -162,19 +192,47 @@ open class GhostedViewLaunchAnimatorController(
return
}
- val scale = min(state.widthRatio, state.heightRatio)
- ghostViewMatrix.setValues(initialGhostViewMatrixValues)
- ghostViewMatrix.postScale(scale, scale, state.startCenterX, state.startCenterY)
+ // The ghost and backgrounds views were made invisible earlier. That can for instance happen
+ // when animating a dialog into a view.
+ if (ghostView.visibility == View.INVISIBLE) {
+ ghostView.visibility = View.VISIBLE
+ backgroundView.visibility = View.VISIBLE
+ }
+
+ fillGhostedViewState(ghostedViewState)
+ val leftChange = state.left - ghostedViewState.left
+ val rightChange = state.right - ghostedViewState.right
+ val topChange = state.top - ghostedViewState.top
+ val bottomChange = state.bottom - ghostedViewState.bottom
+
+ val widthRatio = state.width.toFloat() / ghostedViewState.width
+ val heightRatio = state.height.toFloat() / ghostedViewState.height
+ val scale = min(widthRatio, heightRatio)
+
+ launchContainer.getLocationOnScreen(launchContainerLocation)
+ GhostView.calculateMatrix(ghostedView, launchContainer, ghostViewMatrix)
+ ghostViewMatrix.postScale(
+ scale, scale,
+ ghostedViewState.centerX - launchContainerLocation[0],
+ ghostedViewState.centerY - launchContainerLocation[1]
+ )
ghostViewMatrix.postTranslate(
- (state.leftChange + state.rightChange) / 2f,
- (state.topChange + state.bottomChange) / 2f
+ (leftChange + rightChange) / 2f,
+ (topChange + bottomChange) / 2f
)
ghostView.animationMatrix = ghostViewMatrix
- backgroundView.top = state.top
- backgroundView.bottom = state.bottom
- backgroundView.left = state.left
- backgroundView.right = state.right
+ // We need to take into account the background insets for the background position.
+ val insets = backgroundInsets
+ val topWithInsets = state.top - insets.top
+ val leftWithInsets = state.left - insets.left
+ val rightWithInsets = state.right + insets.right
+ val bottomWithInsets = state.bottom + insets.bottom
+
+ backgroundView.top = topWithInsets - launchContainerLocation[1]
+ backgroundView.bottom = bottomWithInsets - launchContainerLocation[1]
+ backgroundView.left = leftWithInsets - launchContainerLocation[0]
+ backgroundView.right = rightWithInsets - launchContainerLocation[0]
val backgroundDrawable = backgroundDrawable!!
backgroundDrawable.wrapped?.let {
@@ -207,7 +265,7 @@ open class GhostedViewLaunchAnimatorController(
* [drawable] is a [LayerDrawable], this will return the first layer that is a
* [GradientDrawable].
*/
- private fun findGradientDrawable(drawable: Drawable): GradientDrawable? {
+ fun findGradientDrawable(drawable: Drawable): GradientDrawable? {
if (drawable is GradientDrawable) {
return drawable
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
index 659b9fee8656..27658824933a 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
@@ -16,6 +16,7 @@
package com.android.systemui.animation;
+import android.graphics.Path;
import android.util.MathUtils;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
@@ -29,7 +30,97 @@ import android.view.animation.PathInterpolator;
* Utility class to receive interpolators from
*/
public class Interpolators {
- public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+
+ /*
+ * ============================================================================================
+ * Emphasized interpolators.
+ * ============================================================================================
+ */
+
+ /**
+ * The default emphasized interpolator. Used for hero / emphasized movement of content.
+ */
+ public static final Interpolator EMPHASIZED = createEmphasizedInterpolator();
+
+ /**
+ * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that
+ * is disappearing e.g. when moving off screen.
+ */
+ public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator(
+ 0.3f, 0f, 0.8f, 0.15f);
+
+ /**
+ * The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
+ * is appearing e.g. when coming from off screen
+ */
+ public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
+ 0.05f, 0.7f, 0.1f, 1f);
+
+
+ /*
+ * ============================================================================================
+ * Standard interpolators.
+ * ============================================================================================
+ */
+
+ /**
+ * The standard interpolator that should be used on every normal animation
+ */
+ public static final Interpolator STANDARD = new PathInterpolator(
+ 0.2f, 0f, 0f, 1f);
+
+ /**
+ * The standard accelerating interpolator that should be used on every regular movement of
+ * content that is disappearing e.g. when moving off screen.
+ */
+ public static final Interpolator STANDARD_ACCELERATE = new PathInterpolator(
+ 0.3f, 0f, 1f, 1f);
+
+ /**
+ * The standard decelerating interpolator that should be used on every regular movement of
+ * content that is appearing e.g. when coming from off screen.
+ */
+ public static final Interpolator STANDARD_DECELERATE = new PathInterpolator(
+ 0f, 0f, 0f, 1f);
+
+ /*
+ * ============================================================================================
+ * Legacy
+ * ============================================================================================
+ */
+
+ /**
+ * The default legacy interpolator as defined in Material 1. Also known as FAST_OUT_SLOW_IN.
+ */
+ public static final Interpolator LEGACY = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+
+ /**
+ * The default legacy accelerating interpolator as defined in Material 1.
+ * Also known as FAST_OUT_LINEAR_IN.
+ */
+ public static final Interpolator LEGACY_ACCELERATE = new PathInterpolator(0.4f, 0f, 1f, 1f);
+
+ /**
+ * The default legacy decelerating interpolator as defined in Material 1.
+ * Also known as LINEAR_OUT_SLOW_IN.
+ */
+ public static final Interpolator LEGACY_DECELERATE = new PathInterpolator(0f, 0f, 0.2f, 1f);
+
+ /**
+ * Linear interpolator. Often used if the interpolator is for different properties who need
+ * different interpolations.
+ */
+ public static final Interpolator LINEAR = new LinearInterpolator();
+
+ /*
+ * ============================================================================================
+ * Custom interpolators
+ * ============================================================================================
+ */
+
+ public static final Interpolator FAST_OUT_SLOW_IN = LEGACY;
+ public static final Interpolator FAST_OUT_LINEAR_IN = LEGACY_ACCELERATE;
+ public static final Interpolator LINEAR_OUT_SLOW_IN = LEGACY_DECELERATE;
/**
* Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t
@@ -37,12 +128,9 @@ public class Interpolators {
*/
public static final Interpolator FAST_OUT_SLOW_IN_REVERSE =
new PathInterpolator(0.8f, 0f, 0.6f, 1f);
- public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
- public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
public static final Interpolator SLOW_OUT_LINEAR_IN = new PathInterpolator(0.8f, 0f, 1f, 1f);
public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
- public static final Interpolator LINEAR = new LinearInterpolator();
public static final Interpolator ACCELERATE = new AccelerateInterpolator();
public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
@@ -72,6 +160,12 @@ public class Interpolators {
public static final Interpolator TOUCH_RESPONSE_REVERSE =
new PathInterpolator(0.9f, 0f, 0.7f, 1f);
+ /*
+ * ============================================================================================
+ * Functions / Utilities
+ * ============================================================================================
+ */
+
/**
* Calculate the amount of overshoot using an exponential falloff function with desired
* properties, where the overshoot smoothly transitions at the 1.0f boundary into the
@@ -122,4 +216,14 @@ public class Interpolators {
return (float) (1f - 0.5f * (1f - Math.cos(3.14159f * oneMinusFrac * oneMinusFrac)));
}
}
+
+ // Create the default emphasized interpolator
+ private static PathInterpolator createEmphasizedInterpolator() {
+ Path path = new Path();
+ // Doing the same as fast_out_extra_slow_in
+ path.moveTo(0f, 0f);
+ path.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f);
+ path.cubicTo(0.208333f, 0.82f, 0.25f, 1f, 1f, 1f);
+ return new PathInterpolator(path);
+ }
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
new file mode 100644
index 000000000000..3bf6c5ebd091
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
@@ -0,0 +1,355 @@
+/*
+ * 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.animation
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffXfermode
+import android.graphics.drawable.GradientDrawable
+import android.util.Log
+import android.util.MathUtils
+import android.view.View
+import android.view.ViewGroup
+import android.view.animation.AnimationUtils
+import android.view.animation.PathInterpolator
+import kotlin.math.roundToInt
+
+private const val TAG = "LaunchAnimator"
+
+/** A base class to animate a window launch (activity or dialog) from a view . */
+class LaunchAnimator @JvmOverloads constructor(
+ context: Context,
+ private val isForTesting: Boolean = false
+) {
+ companion object {
+ internal const val DEBUG = false
+ const val ANIMATION_DURATION = 500L
+ private const val ANIMATION_DURATION_FADE_OUT_CONTENT = 150L
+ private const val ANIMATION_DURATION_FADE_IN_WINDOW = 183L
+ private const val ANIMATION_DELAY_FADE_IN_WINDOW = ANIMATION_DURATION_FADE_OUT_CONTENT
+
+ private val WINDOW_FADE_IN_INTERPOLATOR = PathInterpolator(0f, 0f, 0.6f, 1f)
+ private val SRC_MODE = PorterDuffXfermode(PorterDuff.Mode.SRC)
+
+ /**
+ * Given the [linearProgress] of a launch animation, return the linear progress of the
+ * sub-animation starting [delay] ms after the launch animation and that lasts [duration].
+ */
+ @JvmStatic
+ fun getProgress(linearProgress: Float, delay: Long, duration: Long): Float {
+ return MathUtils.constrain(
+ (linearProgress * ANIMATION_DURATION - delay) / duration,
+ 0.0f,
+ 1.0f
+ )
+ }
+ }
+
+ /** The interpolator used for the width, height, Y position and corner radius. */
+ private val animationInterpolator = AnimationUtils.loadInterpolator(context,
+ R.interpolator.launch_animation_interpolator_y)
+
+ /** The interpolator used for the X position. */
+ private val animationInterpolatorX = AnimationUtils.loadInterpolator(context,
+ R.interpolator.launch_animation_interpolator_x)
+
+ private val launchContainerLocation = IntArray(2)
+ private val cornerRadii = FloatArray(8)
+
+ /**
+ * A controller that takes care of applying the animation to an expanding view.
+ *
+ * Note that all callbacks (onXXX methods) are all called on the main thread.
+ */
+ interface Controller {
+ /**
+ * The container in which the view that started the animation will be animating together
+ * with the opening window.
+ *
+ * This will be used to:
+ * - Get the associated [Context].
+ * - Compute whether we are expanding fully above the launch container.
+ * - Apply surface transactions in sync with RenderThread when animating an activity
+ * launch.
+ *
+ * This container can be changed to force this [Controller] to animate the expanding view
+ * inside a different location, for instance to ensure correct layering during the
+ * animation.
+ */
+ var launchContainer: ViewGroup
+
+ /**
+ * Return the [State] of the view that will be animated. We will animate from this state to
+ * the final window state.
+ *
+ * Note: This state will be mutated and passed to [onLaunchAnimationProgress] during the
+ * animation.
+ */
+ fun createAnimatorState(): State
+
+ /**
+ * The animation started. This is typically used to initialize any additional resource
+ * needed for the animation. [isExpandingFullyAbove] will be true if the window is expanding
+ * fully above the [launchContainer].
+ */
+ fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {}
+
+ /** The animation made progress and the expandable view [state] should be updated. */
+ fun onLaunchAnimationProgress(state: State, progress: Float, linearProgress: Float) {}
+
+ /**
+ * The animation ended. This will be called *if and only if* [onLaunchAnimationStart] was
+ * called previously. This is typically used to clean up the resources initialized when the
+ * animation was started.
+ */
+ fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {}
+ }
+
+ /** The state of an expandable view during a [LaunchAnimator] animation. */
+ open class State(
+ /** The position of the view in screen space coordinates. */
+ var top: Int = 0,
+ var bottom: Int = 0,
+ var left: Int = 0,
+ var right: Int = 0,
+
+ var topCornerRadius: Float = 0f,
+ var bottomCornerRadius: Float = 0f
+ ) {
+ private val startTop = top
+
+ val width: Int
+ get() = right - left
+
+ val height: Int
+ get() = bottom - top
+
+ open val topChange: Int
+ get() = top - startTop
+
+ val centerX: Float
+ get() = left + width / 2f
+
+ val centerY: Float
+ get() = top + height / 2f
+
+ /** Whether the expanding view should be visible or hidden. */
+ var visible: Boolean = true
+ }
+
+ interface Animation {
+ /** Cancel the animation. */
+ fun cancel()
+ }
+
+ /**
+ * Start a launch animation controlled by [controller] towards [endState]. An intermediary
+ * layer with [windowBackgroundColor] will fade in then fade out above the expanding view, and
+ * should be the same background color as the opening (or closing) window. If [drawHole] is
+ * true, then this intermediary layer will be drawn with SRC blending mode while it fades out.
+ *
+ * TODO(b/184121838): Remove [drawHole] and instead make the StatusBar draw this hole instead.
+ */
+ fun startAnimation(
+ controller: Controller,
+ endState: State,
+ windowBackgroundColor: Int,
+ drawHole: Boolean = false
+ ): Animation {
+ val state = controller.createAnimatorState()
+
+ // Start state.
+ val startTop = state.top
+ val startBottom = state.bottom
+ val startLeft = state.left
+ val startRight = state.right
+ val startCenterX = (startLeft + startRight) / 2f
+ val startWidth = startRight - startLeft
+ val startTopCornerRadius = state.topCornerRadius
+ val startBottomCornerRadius = state.bottomCornerRadius
+
+ // End state.
+ var endTop = endState.top
+ var endBottom = endState.bottom
+ var endLeft = endState.left
+ var endRight = endState.right
+ var endCenterX = (endLeft + endRight) / 2f
+ var endWidth = endRight - endLeft
+ val endTopCornerRadius = endState.topCornerRadius
+ val endBottomCornerRadius = endState.bottomCornerRadius
+
+ fun maybeUpdateEndState() {
+ if (endTop != endState.top || endBottom != endState.bottom ||
+ endLeft != endState.left || endRight != endState.right) {
+ endTop = endState.top
+ endBottom = endState.bottom
+ endLeft = endState.left
+ endRight = endState.right
+ endCenterX = (endLeft + endRight) / 2f
+ endWidth = endRight - endLeft
+ }
+ }
+
+ val launchContainer = controller.launchContainer
+ val isExpandingFullyAbove = isExpandingFullyAbove(launchContainer, endState)
+
+ // We add an extra layer with the same color as the dialog/app splash screen background
+ // color, which is usually the same color of the app background. We first fade in this layer
+ // to hide the expanding view, then we fade it out with SRC mode to draw a hole in the
+ // launch container and reveal the opening window.
+ val windowBackgroundLayer = GradientDrawable().apply {
+ setColor(windowBackgroundColor)
+ alpha = 0
+ }
+
+ // Update state.
+ val animator = ValueAnimator.ofFloat(0f, 1f)
+ animator.duration = if (isForTesting) 0 else ANIMATION_DURATION
+ animator.interpolator = Interpolators.LINEAR
+
+ val launchContainerOverlay = launchContainer.overlay
+ var cancelled = false
+ animator.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animation: Animator?, isReverse: Boolean) {
+ if (DEBUG) {
+ Log.d(TAG, "Animation started")
+ }
+ controller.onLaunchAnimationStart(isExpandingFullyAbove)
+
+ // Add the drawable to the launch container overlay. Overlays always draw
+ // drawables after views, so we know that it will be drawn above any view added
+ // by the controller.
+ launchContainerOverlay.add(windowBackgroundLayer)
+ }
+
+ override fun onAnimationEnd(animation: Animator?) {
+ if (DEBUG) {
+ Log.d(TAG, "Animation ended")
+ }
+ controller.onLaunchAnimationEnd(isExpandingFullyAbove)
+ launchContainerOverlay.remove(windowBackgroundLayer)
+ }
+ })
+
+ animator.addUpdateListener { animation ->
+ if (cancelled) {
+ // TODO(b/184121838): Cancel the animator directly instead of just skipping the
+ // update.
+ return@addUpdateListener
+ }
+
+ maybeUpdateEndState()
+
+ // TODO(b/184121838): Use reverse interpolators to get the same path/arc as the non
+ // reversed animation.
+ val linearProgress = animation.animatedFraction
+ val progress = animationInterpolator.getInterpolation(linearProgress)
+ val xProgress = animationInterpolatorX.getInterpolation(linearProgress)
+
+ val xCenter = MathUtils.lerp(startCenterX, endCenterX, xProgress)
+ val halfWidth = MathUtils.lerp(startWidth, endWidth, progress) / 2f
+
+ state.top = MathUtils.lerp(startTop, endTop, progress).roundToInt()
+ state.bottom = MathUtils.lerp(startBottom, endBottom, progress).roundToInt()
+ state.left = (xCenter - halfWidth).roundToInt()
+ state.right = (xCenter + halfWidth).roundToInt()
+
+ state.topCornerRadius =
+ MathUtils.lerp(startTopCornerRadius, endTopCornerRadius, progress)
+ state.bottomCornerRadius =
+ MathUtils.lerp(startBottomCornerRadius, endBottomCornerRadius, progress)
+
+ // The expanding view can/should be hidden once it is completely covered by the opening
+ // window.
+ state.visible = getProgress(linearProgress, 0, ANIMATION_DURATION_FADE_OUT_CONTENT) < 1
+
+ applyStateToWindowBackgroundLayer(
+ windowBackgroundLayer,
+ state,
+ linearProgress,
+ launchContainer,
+ drawHole
+ )
+ controller.onLaunchAnimationProgress(state, progress, linearProgress)
+ }
+
+ animator.start()
+ return object : Animation {
+ override fun cancel() {
+ cancelled = true
+ animator.cancel()
+ }
+ }
+ }
+
+ /** Return whether we are expanding fully above the [launchContainer]. */
+ internal fun isExpandingFullyAbove(launchContainer: View, endState: State): Boolean {
+ launchContainer.getLocationOnScreen(launchContainerLocation)
+ return endState.top <= launchContainerLocation[1] &&
+ endState.bottom >= launchContainerLocation[1] + launchContainer.height &&
+ endState.left <= launchContainerLocation[0] &&
+ endState.right >= launchContainerLocation[0] + launchContainer.width
+ }
+
+ private fun applyStateToWindowBackgroundLayer(
+ drawable: GradientDrawable,
+ state: State,
+ linearProgress: Float,
+ launchContainer: View,
+ drawHole: Boolean
+ ) {
+ // Update position.
+ launchContainer.getLocationOnScreen(launchContainerLocation)
+ drawable.setBounds(
+ state.left - launchContainerLocation[0],
+ state.top - launchContainerLocation[1],
+ state.right - launchContainerLocation[0],
+ state.bottom - launchContainerLocation[1]
+ )
+
+ // Update radius.
+ cornerRadii[0] = state.topCornerRadius
+ cornerRadii[1] = state.topCornerRadius
+ cornerRadii[2] = state.topCornerRadius
+ cornerRadii[3] = state.topCornerRadius
+ cornerRadii[4] = state.bottomCornerRadius
+ cornerRadii[5] = state.bottomCornerRadius
+ cornerRadii[6] = state.bottomCornerRadius
+ cornerRadii[7] = state.bottomCornerRadius
+ drawable.cornerRadii = cornerRadii
+
+ // We first fade in the background layer to hide the expanding view, then fade it out
+ // with SRC mode to draw a hole punch in the status bar and reveal the opening window.
+ val fadeInProgress = getProgress(linearProgress, 0, ANIMATION_DURATION_FADE_OUT_CONTENT)
+ if (fadeInProgress < 1) {
+ val alpha = Interpolators.LINEAR_OUT_SLOW_IN.getInterpolation(fadeInProgress)
+ drawable.alpha = (alpha * 0xFF).roundToInt()
+ } else {
+ val fadeOutProgress = getProgress(
+ linearProgress, ANIMATION_DELAY_FADE_IN_WINDOW, ANIMATION_DURATION_FADE_IN_WINDOW)
+ val alpha = 1 - WINDOW_FADE_IN_INTERPOLATOR.getInterpolation(fadeOutProgress)
+ drawable.alpha = (alpha * 0xFF).roundToInt()
+
+ if (drawHole) {
+ drawable.setXfermode(SRC_MODE)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_backspace_24dp.xml b/packages/SystemUI/res-keyguard/drawable/ic_backspace_24dp.xml
index dd35dd91f5d6..1eec8204a7f2 100644
--- a/packages/SystemUI/res-keyguard/drawable/ic_backspace_24dp.xml
+++ b/packages/SystemUI/res-keyguard/drawable/ic_backspace_24dp.xml
@@ -20,6 +20,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="?android:attr/colorBackground"
+ android:fillColor="?android:attr/textColorPrimaryInverse"
android:pathData="M9,15.59L12.59,12L9,8.41L10.41,7L14,10.59L17.59,7L19,8.41L15.41,12L19,15.59L17.59,17L14,13.41L10.41,17L9,15.59zM21,6H8l-4.5,6L8,18h13V6M21,4c1.1,0 2,0.9 2,2v12c0,1.1 -0.9,2 -2,2H8c-0.63,0 -1.22,-0.3 -1.6,-0.8L1,12l5.4,-7.2C6.78,4.3 7.37,4 8,4H21L21,4z"/>
</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml b/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml
index b844515f1088..2ad5e54eb92a 100644
--- a/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml
+++ b/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml
@@ -19,7 +19,8 @@
android:viewportHeight="36"
android:viewportWidth="36"
android:width="36sp">
- <path android:fillColor="?android:attr/colorBackground"
+
+ <path android:fillColor="?android:attr/textColorPrimaryInverse"
android:pathData="M17.59,13.41L21.17,17H7v2h14.17l-3.59,3.59L19,24l6,-6l-6,-6L17.59,
13.41zM26,12v12h2V12H26z"/>
</vector>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 624ee9f51b2a..6fd83c55b656 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -17,7 +17,8 @@
*/
-->
-<resources>
+<resources
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<!-- Keyguard PIN pad styles -->
<style name="Keyguard.TextView" parent="@android:style/Widget.DeviceDefault.TextView">
<item name="android:textSize">@dimen/kg_status_line_font_size</item>
@@ -58,11 +59,11 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="NumPadKey.Delete">
- <item name="android:colorControlNormal">?android:attr/textColorSecondary</item>
+ <item name="android:colorControlNormal">?androidprv:attr/colorAccentSecondaryVariant</item>
<item name="android:src">@drawable/ic_backspace_24dp</item>
</style>
<style name="NumPadKey.Enter">
- <item name="android:colorControlNormal">?android:attr/textColorSecondary</item>
+ <item name="android:colorControlNormal">?androidprv:attr/colorAccentSecondaryVariant</item>
<item name="android:src">@drawable/ic_keyboard_tab_36dp</item>
</style>
<style name="Widget.TextView.NumPadKey.Klondike"
diff --git a/packages/SystemUI/res/drawable/media_output_dialog_background.xml b/packages/SystemUI/res/drawable/media_output_dialog_background.xml
deleted file mode 100644
index 3ceb0f6ac06a..000000000000
--- a/packages/SystemUI/res/drawable/media_output_dialog_background.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<inset xmlns:android="http://schemas.android.com/apk/res/android">
- <shape android:shape="rectangle">
- <corners android:radius="8dp" />
- <solid android:color="?android:attr/colorBackground" />
- </shape>
-</inset>
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index 918635d666fa..c1d7308be5a8 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -19,7 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/internet_connectivity_dialog"
- android:layout_width="@dimen/internet_dialog_list_max_width"
+ android:layout_width="@dimen/large_dialog_width"
android:layout_height="@dimen/internet_dialog_list_max_height"
android:background="@drawable/internet_dialog_rounded_top_corner_background"
android:orientation="vertical">
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index d996cee4b39e..b33889469f48 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -18,7 +18,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/media_output_dialog"
- android:layout_width="match_parent"
+ android:layout_width="@dimen/large_dialog_width"
android:layout_height="wrap_content"
android:orientation="vertical">
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index 566cd25e86a5..b546a9cbe90e 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -134,6 +134,7 @@
android:background="@drawable/qs_media_light_source"
android:forceHasOverlappingRendering="false">
<LinearLayout
+ android:id="@+id/media_seamless_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="@dimen/qs_seamless_height"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 5cd99f29bbab..f589498c377a 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Ontsluit om netwerke te bekyk"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Soek tans na netwerke …"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kon nie aan netwerk koppel nie"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-fi sal vir nou nie outomaties koppel nie"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Sien alles"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ontkoppel Ethernet om netwerke te wissel"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 2f485ada1186..e94dc688ac7c 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"አውታረ መረቦችን ለመመልከት ይክፈቱ"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"አውታረ መረቦችን በመፈለግ ላይ…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"ከአውታረ መረቡ ጋር መገናኘት አልተሳካም"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wifi ለአሁን በራስ-ሰር አይገናኝም"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ሁሉንም ይመልከቱ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"አውታረ መረቦችን ለመቀየር፣ የኢተርኔት ግንኙነት ያቋርጡ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 81a7f7c29ff2..14753dabb464 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -1199,6 +1199,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"فتح القفل لعرض الشبكات"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"جارٍ البحث عن شبكات…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"تعذّر الاتصال بالشبكة."</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"‏لن يتم الاتصال بشبكة Wi-Fi تلقائيًا في الوقت الحالي."</string>
<string name="see_all_networks" msgid="3773666844913168122">"عرض الكل"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"للتبديل بين الشبكات، يجب فصل إيثرنت."</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index d73fd7357c5d..a50d8c10dd3f 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"নেটৱর্ক চাবলৈ আনলক কৰক"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"নেটৱৰ্ক সন্ধান কৰি থকা হৈছে…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"নেটৱৰ্কৰ সৈতে সংযোগ কৰিব পৰা নগ\'ল"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"এতিয়া ৱাই-ফাই স্বয়ংক্ৰিয়ভাৱে সংযুক্ত নহ’ব"</string>
<string name="see_all_networks" msgid="3773666844913168122">"আটাইবোৰ চাওক"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"নেটৱৰ্ক সলনি কৰিবলৈ ইথাৰনেটৰ পৰা সংযোগ বিচ্ছিন্ন কৰক"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index f7746e8b6397..e0ef1eca3282 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Şəbəkələrə baxmaq üçün kilidi açın"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Şəbəkə axtarılır…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Şəbəkəyə qoşulmaq alınmadı"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi hələlik avtomatik qoşulmayacaq"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Hamısına baxın"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Şəbəkəni dəyişmək üçün etherneti ayırın"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 72efc72a36f2..31f8014e8b6c 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -1181,6 +1181,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte da biste videli mreže"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traže se mreže…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje sa mrežom nije uspelo"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi trenutno ne može da se automatski poveže"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Pogledajte sve"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da biste promenili mrežu, prekinite eternet vezu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index f7c20ab54895..b296aa63eedb 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -1187,6 +1187,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Разблакіраваць для прагляду сетак"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Выконваецца пошук сетак…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не ўдалося падключыцца да сеткі"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Аўтаматычнае падключэнне да Wi-Fi адсутнічае"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Паказаць усе"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Каб падключыцца да сетак, выключыце Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index b4164a003a1a..84c22912a322 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Отключване с цел преглед на мрежите"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Търсят се мрежи…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Свързването с мрежата не бе успешно"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Засега Wi-Fi няма да се свързва автоматично"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Вижте всички"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"За да превключите мрежите, прекъснете връзката с Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 92da7de7286e..93ac0404fe87 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -1175,6 +1175,8 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"নেটওয়ার্ক দেখার জন্য আনলক করুন"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"নেটওয়ার্ক সার্চ করা হচ্ছে…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"নেটওয়ার্কে কানেক্ট করা যায়নি"</string>
+ <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+ <skip />
<string name="see_all_networks" msgid="3773666844913168122">"সবকটি দেখুন"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"নেটওয়ার্ক বদলাতে ইথারনেট ডিসকানেক্ট করুন"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index e913d56be38b..c8588ecd4cdd 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -1181,6 +1181,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte da vidite mreže"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traženje mreža…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje s mrežom nije uspjelo"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi se trenutno ne može automatski povezati"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da promijenite mrežu, isključite ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index be384e372993..cfe70c2a22c9 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueja per veure xarxes"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"S\'estan cercant xarxes…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"No s\'ha pogut connectar a la xarxa"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Per ara la Wi‑Fi no es connectarà automàticament"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Mostra-ho tot"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Per canviar de xarxa, desconnecta la connexió Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 5be30774348c..3d648cb03309 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -1187,6 +1187,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Sítě uvidíte po odemknutí"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Vyhledávání sítí…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Připojení k síti se nezdařilo"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi se prozatím nebude připojovat automaticky"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Zobrazit vše"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pokud chcete přepnout sítě, odpojte ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 2c7ffe5154b1..eb715aa8e7ca 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås op for at se netværk"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Søger efter netværk…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Der kunne ikke oprettes forbindelse til netværket"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Ingen automatisk forbindelse til Wi-Fi i øjeblikket"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Afbryd ethernetforbindelsen for at skifte netværk"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 9c39acdd56f2..b8154923bd63 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Entsperren, um Netzwerke anzuzeigen"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Netzwerke werden gesucht…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Netzwerkverbindung konnte nicht hergestellt werden"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Zurzeit wird keine automatische WLAN-Verbindung hergestellt"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Alle ansehen"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Trenne das Ethernetkabel, um das Netzwerk zu wechseln"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 8705ad094e86..c6cc7f0d4212 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Ξεκλειδώστε για προβολή δικτύων"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Αναζήτηση δικτύων…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Αποτυχία σύνδεσης στο δίκτυο"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Δεν θα γίνεται προς το παρόν αυτόματη σύνδεση Wi-Fi."</string>
<string name="see_all_networks" msgid="3773666844913168122">"Εμφάνιση όλων"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Για εναλλαγή δικτύων, αποσυνδέστε το ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index a2bcfd1a41eb..e1006fc83780 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string>
<string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 1cc3cd37a8e5..66b44d5ecf8b 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string>
<string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index a2bcfd1a41eb..e1006fc83780 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string>
<string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index a2bcfd1a41eb..e1006fc83780 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string>
<string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 71a1c2fb5f34..9af7322e8507 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎Unlock to view networks‎‏‎‎‏‎"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‎‎‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎Searching for networks…‎‏‎‎‏‎"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‎‎‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‏‏‏‎Failed to connect to network‎‏‎‎‏‎"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‎Wi‑Fi won’t auto-connect for now‎‏‎‎‏‎"</string>
<string name="see_all_networks" msgid="3773666844913168122">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎See all‎‏‎‎‏‎"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‏‎To switch networks, disconnect ethernet‎‏‎‎‏‎"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 0454e73be3d8..8d53bb99f3e0 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea para ver las redes"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Se produjo un error al establecer conexión con la red"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por ahora, el Wi-Fi no se conectará automáticamente"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconéctate de Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 0751362138bf..c0c12fa7ddc8 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea para ver redes"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"No se ha podido conectar a la red"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por ahora no se conectará automáticamente a redes Wi-Fi"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconecta el cable Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 16920069b3db..c3cb5520db83 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Võrkude vaatamiseks avage"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Võrkude otsimine …"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Võrguühenduse loomine ebaõnnestus"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi-ühendust ei looda praegu automaatselt"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Kuva kõik"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Võrkude vahetamiseks katkestage Etherneti-ühendus"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 8055cfec1994..8df329a899e3 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -845,7 +845,7 @@
<string name="keyboard_shortcut_group_applications_browser" msgid="2776211137869809251">"Arakatzailea"</string>
<string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"Kontaktuak"</string>
<string name="keyboard_shortcut_group_applications_email" msgid="7852376788894975192">"Posta"</string>
- <string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS mezuak"</string>
+ <string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMSak"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musika"</string>
<string name="keyboard_shortcut_group_applications_youtube" msgid="5078136084632450333">"YouTube"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Sareak ikusteko, desblokeatu pantaila"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Sareak bilatzen…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ezin izan da konektatu sarera"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Oraingoz ez da automatikoki konektatuko wifira"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Ikusi guztiak"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Sarea aldatzeko, deskonektatu Ethernet-a"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 74f23ac3bbd8..ae308b7ed434 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"برای مشاهده شبکه‌ها، قفل صفحه را باز کنید"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"درحال جستجوی شبکه…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"اتصال به شبکه برقرار نشد"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"‏فعلاً Wi-Fi به‌طور خودکار متصل نمی‌شود"</string>
<string name="see_all_networks" msgid="3773666844913168122">"مشاهده همه"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"برای تغییر شبکه، اترنت را قطع کنید"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index f1144072f0d3..ee0cdb65a83d 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Avaa lukitus nähdäksesi verkot"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Etsitään verkkoja…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Yhteyden muodostaminen verkkoon epäonnistui"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi ei toistaiseksi yhdistä automaattisesti"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Näytä kaikki"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Irrota Ethernet-johto, jos haluat vaihtaa verkkoa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 35ed848a17a3..7fcbcfb6eb0b 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Déverrouillez l\'écran pour afficher les réseaux Wi-Fi"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Recherche de réseaux en cours…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Échec de la connexion au réseau"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Connexion automatique au Wi-Fi impossible pour le moment"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, débranchez le câble Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 514c434be920..74e55fc90687 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Déverrouiller pour afficher les réseaux"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Recherche de réseaux…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Échec de la connexion au réseau"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Connexion automatique au Wi-Fi désactivée pour le moment"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, déconnectez l\'Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 1eba1ed4d301..3bcfcc8e6a88 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea a pantalla para ver as redes"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Produciuse un erro ao conectarse á rede"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"De momento, a wifi non se conectará automaticamente"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de rede, desconecta a Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 2c4e6e5627fb..79281156e00b 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -1175,6 +1175,8 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"વાઇ-ફાઇ નેટવર્ક જોવા માટે અનલૉક કરો"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"નેટવર્ક શોધી રહ્યાં છીએ…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"નેટવર્ક સાથે કનેક્ટ કરવામાં નિષ્ફળ થયાં"</string>
+ <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+ <skip />
<string name="see_all_networks" msgid="3773666844913168122">"બધા જુઓ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"બીજા નેટવર્ક પર જવા માટે, ઇથરનેટ ડિસ્કનેક્ટ કરો"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 3eb45ea8ee82..edd7fc6799bf 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"वाई-फ़ाई नेटवर्क देखने के लिए, स्क्रीन को अनलॉक करें"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्क खोजे जा रहे हैं…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्क से कनेक्ट नहीं किया जा सका"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"फ़िलहाल, वाई-फ़ाई अपने-आप कनेक्ट नहीं होगा"</string>
<string name="see_all_networks" msgid="3773666844913168122">"सभी देखें"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क बदलने के लिए, पहले ईथरनेट को डिसकनेक्ट करें"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 97dbf591a84f..b066191b021a 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -1181,6 +1181,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte za prikaz mreža"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traženje mreža…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje s mrežom nije uspjelo"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi se zasad neće automatski povezivati"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da biste se prebacili na drugu mrežu, odspojite Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index ddff2c20cb9c..5880cf0abb02 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Zárolás feloldása a hálózatok megtekintéséhez"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Hálózatok keresése…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nem sikerült hálózathoz csatlakozni."</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"A Wi-Fi-re történő csatlakozás jelenleg nem automatikus"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Megtekintés"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Hálózatváltáshoz válassza le az ethernetet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 3100b9c72000..ad3cf25467d9 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Ապակողպեք՝ ցանցերը դիտելու համար"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ցանցերի որոնում…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Չհաջողվեց միանալ ցանցին"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi-ն ավտոմատ չի միանա"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Տեսնել բոլորը"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Մի ցանցից մյուսին անցնելու համար անջատեք Ethernet-ը"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 80f6ed4d4ed7..c42b143709c1 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Buka kunci untuk melihat jaringan"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Mencari jaringan …"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Gagal menghubungkan ke jaringan"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi tidak akan otomatis terhubung untuk saat ini"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Untuk beralih jaringan, lepaskan kabel ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 2732b71dca14..469228065c8d 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Taktu úr lás til að skoða netkerfi"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Leitar að netum…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ekki tókst að tengjast neti"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi tengist ekki sjálfkrafa eins og er"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Sjá allt"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Aftengdu ethernet til að skipta um net"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 9410c99ad54c..1d96598be708 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Sblocca per visualizzare le reti"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ricerca di reti in corso…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Connessione alla rete non riuscita"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Connessione automatica rete Wi-Fi non attiva al momento"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Mostra tutte"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Per cambiare rete, scollega il cavo Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index f6b74c389305..8fd2bb9abf22 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -1187,6 +1187,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"צריך לבטל את הנעילה כדי להציג את הרשתות"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"בתהליך חיפוש רשתות…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"נכשל הניסיון להתחבר לרשת"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"‏ה-Wi-Fi לא יתחבר באופן אוטומטי בינתיים"</string>
<string name="see_all_networks" msgid="3773666844913168122">"הצגת הכול"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"כדי לעבור בין רשתות, צריך לנתק את האתרנט"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index aa6aa3c7f374..3134f73605c1 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"ネットワークを表示するにはロック解除してください"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ネットワークを検索しています…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"ネットワークに接続できませんでした"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi に自動接続しません"</string>
<string name="see_all_networks" msgid="3773666844913168122">"すべて表示"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ネットワークを変更するにはイーサネット接続を解除してください"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index ac604701827d..c4c73c5cb912 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"განბლოკვა ქსელების სანახავად"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"მიმდინარეობს ქსელების ძიება…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"ქსელთან დაკავშირება ვერ ხერხდება"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi ინტერნეტს დროებით ავტომატურად არ დაუკავშირდება"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ყველას ნახვა"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ქსელების გადასართავად, გაწყვიტეთ Ethernet-თან კავშირი"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index fd2bcc7df5a2..bccc0ab7d937 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Желілерді көру үшін құлыпты ашыңыз."</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Маңайдағы желілер ізделуде…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Желіге қосылмады."</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Әзірше Wi-Fi автоматты түрде қосылмайды."</string>
<string name="see_all_networks" msgid="3773666844913168122">"Барлығын көру"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Желілерді ауыстыру үшін ethernet кабелін ажыратыңыз."</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 035319ef682b..7d79023c1c61 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"ដោះសោ​ដើម្បីមើល​បណ្ដាញ"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"កំពុងស្វែងរកបណ្ដាញ…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"មិន​អាច​ភ្ជាប់​បណ្ដាញ​បានទេ"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi នឹងមិន​ភ្ជាប់ដោយស្វ័យ​ប្រវត្តិក្នុងពេលនេះទេ"</string>
<string name="see_all_networks" msgid="3773666844913168122">"មើលទាំងអស់"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ដើម្បី​ប្ដូរ​បណ្ដាញ សូមផ្ដាច់​អ៊ីសឺរណិត"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 1d8fbb3fe777..0a28735aadd1 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -1175,6 +1175,8 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"</string>
+ <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+ <skip />
<string name="see_all_networks" msgid="3773666844913168122">"ಎಲ್ಲವನ್ನೂ ನೋಡಿ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ಬದಲಿಸಲು, ಇಥರ್ನೆಟ್ ಅನ್ನು ಡಿಸ್‌ಕನೆಕ್ಟ್ ಮಾಡಿ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 751bfd8a8e32..3a8657ba30a6 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"네트워크를 보려면 잠금 해제하세요"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"네트워크 검색 중…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"네트워크에 연결하지 못했습니다."</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"지금은 Wi-Fi가 자동으로 연결되지 않습니다."</string>
<string name="see_all_networks" msgid="3773666844913168122">"모두 보기"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"네트워크를 전환하려면 이더넷을 연결 해제하세요."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 343457226160..9f242f34b300 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Тармактарды көрүү үчүн кулпусун ачыңыз"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Тармактар изделүүдө…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Тармакка туташпай калды"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi азырынча автоматтык түрдө туташпайт"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Баарын көрүү"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Башка тармактарга которулуу үчүн Ethernet кабелин ажыратыңыз"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index b603ca6ac06e..afd914d738ae 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"ປົດລັອກເພື່ອເບິ່ງເຄືອຂ່າຍ"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ກຳລັງຊອກຫາເຄືອຂ່າຍ…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"ເຊື່ອມຕໍ່ເຄືອຂ່າຍບໍ່ສຳເລັດ"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi ຈະບໍ່ເຊື່ອມຕໍ່ອັດຕະໂນມັດສຳລັບຕອນນີ້"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ເບິ່ງທັງໝົດ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ເພື່ອສະຫຼັບເຄືອຂ່າຍ, ໃຫ້ຕັດການເຊື່ອມຕໍ່ອີເທີເນັດກ່ອນ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 657c95b79534..233610f00cd0 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -1187,6 +1187,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Atrakinkite, kad peržiūrėtumėte visus tinklus"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ieškoma tinklų…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Jungiantis prie tinklo įvyko klaida"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"„Wi-Fi“ šiuo metu nebus prijungtas automatiškai"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Žiūrėti viską"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Norėdami perjungti tinklus, atjunkite eternetą"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index f5927db7c26c..83e6d6e514ea 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -1181,6 +1181,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Lai skatītu tīklus, atbloķējiet"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Notiek tīklu meklēšana…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Neizdevās izveidot savienojumu ar tīklu"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi savienojums īslaicīgi netiks izveidots automātiski."</string>
<string name="see_all_networks" msgid="3773666844913168122">"Visu tīklu skatīšana"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Lai pārslēgtu tīklus, atvienojiet tīkla Ethernet vadu."</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 396fab5d1444..e00108a7b9fb 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Отклучете за да се прикажат мрежите"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Се пребаруваат мрежи…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не успеа да се поврзе на мрежата"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi нема да се поврзува автоматски засега"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Прикажи ги сите"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"За промена на мрежата, прекинете ја врската со етернетот"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 6d92e8a46b5e..49beea2dcb32 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"നെറ്റ്‌വർക്കുകൾ കാണാൻ അൺ‌ലോക്ക് ചെയ്യുക"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"നെറ്റ്‌വർക്കുകൾ തിരയുന്നു…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"നെറ്റ്‌വർക്കിൽ കണക്റ്റ് ചെയ്യാനായില്ല"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"വൈഫൈ ഇപ്പോൾ സ്വയമേവ കണക്റ്റ് ചെയ്യില്ല"</string>
<string name="see_all_networks" msgid="3773666844913168122">"എല്ലാം കാണുക"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"മറ്റ് നെറ്റ്‌വർക്കുകളിലേക്ക് മാറാൻ, ഇതർനെറ്റ് വിച്ഛേദിക്കുക"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 3968d52a84f4..f6dea18f0417 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Сүлжээг харахын тулд түгжээг тайлах"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Сүлжээ хайж байна…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Сүлжээнд холбогдож чадсангүй"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi-г одоогоор автоматаар холбохгүй"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Бүгдийг харах"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Сүлжээг сэлгэхийн тулд этернэтийг салгана уу"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 69c829c496c8..6156cf592def 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"नेटवर्क पाहण्यासाठी स्क्रीन अनलॉक करा"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्क शोधत आहे…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्कशी कनेक्‍ट करता आले नाही"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"सध्या वाय-फाय ऑटो-कनेक्ट होणार नाही"</string>
<string name="see_all_networks" msgid="3773666844913168122">"सर्व पहा"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क स्विच करण्यासाठी, इथरनेट केबल डिस्कनेक्ट करा"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index ebe0094d3392..9dde6b667bc5 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Buka kunci untuk melihat rangkaian"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Mencari rangkaian…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Gagal menyambung kepada rangkaian"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi tidak akan disambungkan secara automatik buat masa ini"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Untuk menukar rangkaian, putuskan sambungan ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 42ed54c91ac4..50fb26c7a297 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"ကွန်ရက်များကြည့်ရန် ဖွင့်ပါ"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ကွန်ရက်များကို ရှာဖွေနေသည်…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"ကွန်ရက်သို့ ချိတ်ဆက်၍မရပါ"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi က ယခု အလိုအလျောက် ချိတ်ဆက်မည်မဟုတ်ပါ"</string>
<string name="see_all_networks" msgid="3773666844913168122">"အားလုံးကြည့်ရန်"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ကွန်ရက်ပြောင်းရန် အီသာနက်ကို ချိတ်ဆက်မှုဖြုတ်ပါ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 3337aa1daeef..d4eef721d76e 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås opp for å se nettverk"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Søker etter nettverk …"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kunne ikke koble til nettverket"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi kobles ikke til automatisk inntil videre"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"For å bytte nettverk, koble fra Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index a7113f3c0081..ce1787c26897 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"नेटवर्कहरू हेर्न आफ्नो स्क्रिन अनलक गर्नुहोस्"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्कहरू खोजिँदै छन्…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्कमा कनेक्ट गर्न सकिएन"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"केही समयका लागि Wi-Fi स्वतः कनेक्ट हुँदैन"</string>
<string name="see_all_networks" msgid="3773666844913168122">"सबै नेटवर्क हेर्नुहोस्"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क बदल्न इथरनेट डिस्कनेक्ट गर्नुहोस्"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index ea9822980b07..ad1403e664df 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Ontgrendel het scherm om netwerken te bekijken"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Netwerken zoeken…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kan geen verbinding maken met het netwerk"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wifi maakt momenteel niet automatisch verbinding"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Alles tonen"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Verbreek de ethernetverbinding om van netwerk te wisselen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 1ea599f12c20..e5c2a2b61825 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"ନେଟୱାର୍କଗୁଡ଼ିକୁ ଦେଖିବା ପାଇଁ ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ନେଟୱାର୍କଗୁଡ଼ିକ ସନ୍ଧାନ କରାଯାଉଛି…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"ନେଟୱାର୍କକୁ ସଂଯୋଗ କରିବାରେ ବିଫଳ ହୋଇଛି"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ବର୍ତ୍ତମାନ ପାଇଁ ୱାଇ-ଫାଇ ସ୍ୱତଃ-ସଂଯୋଗ ହେବ ନାହିଁ"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ସବୁ ଦେଖନ୍ତୁ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ନେଟୱାର୍କ ସ୍ୱିଚ୍ କରିବାକୁ, ଇଥରନେଟ୍ ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 06364eaabe1f..48750cf95731 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ਨੈੱਟਵਰਕ ਖੋਜੇ ਜਾ ਰਹੇ ਹਨ…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ਫ਼ਿਲਹਾਲ ਵਾਈ-ਫਾਈ ਸਵੈ-ਕਨੈਕਟ ਨਹੀਂ ਹੋਵੇਗਾ"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ਸਭ ਦੇਖੋ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਬਦਲਣ ਲਈ, ਈਥਰਨੈੱਟ ਨੂੰ ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index ae4b5d60727b..3635876b04da 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -1187,6 +1187,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Odblokuj, by wyświetlić sieci"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Szukam sieci…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nie udało się połączyć z siecią"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi nie będzie na razie włączać się automatycznie"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Pokaż wszystko"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Aby przełączać sieci, odłącz Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index cbd43f878e08..8f499f7fbb04 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Procurando redes…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Falha ao conectar à rede"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"A conexão automática ao Wi-Fi ficará indisponível"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desconecte o cabo Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index a8f62585dc38..b0c65d866b78 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"A procurar redes…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Não foi possível estabelecer ligação à rede"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por agora, o Wi-Fi não irá estabelecer lig. automaticamente"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Veja tudo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desligue a Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index cbd43f878e08..8f499f7fbb04 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Procurando redes…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Falha ao conectar à rede"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"A conexão automática ao Wi-Fi ficará indisponível"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desconecte o cabo Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 751ea3ac4270..c143d5349ad4 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -1181,6 +1181,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Deblocați pentru a vedea rețelele"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Se caută rețele…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nu s-a realizat conexiunea la rețea"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Deocamdată, Wi-Fi nu se poate conecta automat"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Afișează-le pe toate"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pentru a schimba rețeaua, deconectați ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 4452a0206c7e..752110ea59ec 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -1187,6 +1187,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Разблокируйте, чтобы посмотреть сети Wi-Fi."</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Поиск сетей…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не удалось подключиться к сети"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Подключение по Wi-Fi не установится автоматически."</string>
<string name="see_all_networks" msgid="3773666844913168122">"Показать все"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Чтобы переключиться между сетями, отключите кабель Ethernet."</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index e87aefb1db58..b3a7a8e3cf7f 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"ජාල බැලීමට අගුලු හරින්න"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ජාල සඳහා සොයමින්…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"ජාලය වෙත සම්බන්ධ වීම අසාර්ථක විය"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi දැනට ස්වයං-සබැඳි නොවනු ඇත"</string>
<string name="see_all_networks" msgid="3773666844913168122">"සියල්ල බලන්න"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ජාල මාරු කිරීමට, ඊතර්නෙට් විසන්ධි කරන්න"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index a1719f060ece..f45226b41ffc 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -1187,6 +1187,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Odomknutím si zobrazte siete"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Vyhľadávajú sa siete…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nepodarilo sa pripojiť k sieti"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi sa teraz automaticky nepripojí"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Zobraziť všetko"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ak chcete prepnúť siete, odpojte ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 7d86eb1f94df..ed753906d8f1 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -1187,6 +1187,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Odklenite za ogled omrežij"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Iskanje omrežij …"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Vzpostavljanje povezave z omrežjem ni uspelo."</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Vmesnik Wi-Fi trenutno ne bo samodejno vzpostavil povezave."</string>
<string name="see_all_networks" msgid="3773666844913168122">"Prikaz vseh omrežij"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Če želite preklopiti omrežje, prekinite ethernetno povezavo."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index c5eb836f3d95..dc7e82564df0 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Shkyçe për të parë rrjetet"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Po kërkon për rrjete…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Lidhja me rrjetin dështoi"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi nuk do të lidhet automatikisht për momentin"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Shiko të gjitha"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Për të ndërruar rrjetet, shkëput Ethernet-in"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index b75535a132bf..b486589b3bd5 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -1181,6 +1181,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Откључајте да бисте видели мреже"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Траже се мреже…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Повезивање са мрежом није успело"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi тренутно не може да се аутоматски повеже"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Погледајте све"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Да бисте променили мрежу, прекините етернет везу"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index b0ef22502cd2..5db089bccc58 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås upp för att visa nätverk"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Söker efter nätverk …"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Det gick inte att ansluta till nätverket"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Du ansluts inte till wifi automatiskt för närvarande"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Visa alla"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Koppla bort Ethernet för att växla nätverk"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index fa1517a23802..60104f623848 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -82,7 +82,7 @@
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Inahifadhi picha ya skrini..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Inahifadhi picha ya skrini..."</string>
<string name="screenshot_saved_title" msgid="8893267638659083153">"Imehifadhi picha ya skrini"</string>
- <string name="screenshot_saved_text" msgid="7778833104901642442">"Gusa ili utazame picha ya skrini uliyohifadhi"</string>
+ <string name="screenshot_saved_text" msgid="7778833104901642442">"Gusa ili uone picha ya skrini uliyohifadhi"</string>
<string name="screenshot_failed_title" msgid="3259148215671936891">"Imeshindwa kuhifadhi picha ya skrini"</string>
<string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"Ni sharti ufungue kifaa kabla ya kuhifadhi picha ya skrini"</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Jaribu kupiga picha ya skrini tena"</string>
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Fungua ili uangalie mitandao"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Inatafuta mitandao…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Imeshindwa kuunganisha kwenye mtandao"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi haitaunganishwa kiotomatiki kwa sasa"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Angalia yote"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ili kubadili mitandao, tenganisha ethaneti"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index d921d4958090..85f8f0957a08 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -104,6 +104,6 @@
<!-- When split shade is used, this panel should be aligned to the top -->
<dimen name="qs_detail_margin_top">0dp</dimen>
- <!-- Internet panel related dimensions -->
- <dimen name="internet_dialog_list_max_width">624dp</dimen>
+ <!-- The width of large/content heavy dialogs (e.g. Internet, Media output, etc) -->
+ <dimen name="large_dialog_width">624dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 5e6e4c60dc89..8cc4c8dd5336 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"நெட்வொர்க்குகளைப் பார்க்க அன்லாக் செய்யுங்கள்"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"நெட்வொர்க்குகளைத் தேடுகிறது…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"நெட்வொர்க்குடன் இணைக்க முடியவில்லை"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"தற்போதைக்கு வைஃபை தானாக இணைக்கப்படாது"</string>
<string name="see_all_networks" msgid="3773666844913168122">"அனைத்தையும் காட்டு"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"நெட்வொர்க்குகளை மாற்ற ஈதர்நெட் இணைப்பைத் துண்டிக்கவும்"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index f4d93ac3fcee..dda2830bbc8c 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"నెట్‌వర్క్‌లను చూడటానికి అన్‌లాక్ చేయండి"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"నెట్‌వర్క్‌ల కోసం సెర్చ్ చేస్తోంది…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"నెట్‌వర్క్‌కు కనెక్ట్ చేయడం విఫలమైంది"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ప్రస్తుతానికి Wi-Fi ఆటోమేటిక్‌గా కనెక్ట్ అవ్వదు"</string>
<string name="see_all_networks" msgid="3773666844913168122">"అన్నీ చూడండి"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"నెట్‌వర్క్‌లను మార్చడానికి, ఈథర్‌నెట్‌ను డిస్‌కనెక్ట్ చేయండి"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index d0603a9ea149..91a24403f4d0 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"ปลดล็อกเพื่อดูเครือข่าย"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"กำลังค้นหาเครือข่าย…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"เชื่อมต่อเครือข่ายไม่สำเร็จ"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi จะไม่เชื่อมต่ออัตโนมัติในตอนนี้"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ดูทั้งหมด"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ตัดการเชื่อมต่ออีเทอร์เน็ตเพื่อสลับเครือข่าย"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index bb1cbe8d8ee9..dcde0fc67584 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"I-unlock para tingnan ang mga network"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Naghahanap ng mga network…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Hind nakakonekta sa network"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Hindi awtomatikong kokonekta ang Wi-Fi sa ngayon"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Tingnan lahat"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para lumipat ng network, idiskonekta ang ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 15b702c384ee..367d0bf3e372 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Ağları görmek için kilidi açın"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ağlar aranıyor…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ağa bağlanılamadı"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Şu anda kablosuz ağa otomatik olarak bağlanılamıyor"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Tümünü göster"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ağ değiştirmek için ethernet bağlantısını kesin"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index dc30e0beaafb..e692a36985b1 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -1187,6 +1187,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Розблокувати, щоб переглянути мережі"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Пошук мереж…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не вдалося підключитися до мережі"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Пристрій не підключатиметься до Wi-Fi автоматично"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Показати все"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Щоб вибрати іншу мережу, від’єднайте кабель Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 667a9577ef3e..da431826c278 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -1175,6 +1175,8 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"نیٹ ورکس کو دیکھنے کے لیے غیر مقفل کریں"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"نیٹ ورکس تلاش کیے جا رہے ہیں…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"نیٹ ورک سے منسلک ہونے میں ناکام ہو گیا"</string>
+ <!-- no translation found for wifi_wont_autoconnect_for_now (5782282612749867762) -->
+ <skip />
<string name="see_all_networks" msgid="3773666844913168122">"سبھی دیکھیں"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"نیٹ ورکس پر سوئچ کرنے کیلئے، ایتھرنیٹ غیر منسلک کریں"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index b02ef403bfeb..f0afb6cb704b 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Tarmoqlarni koʻrish uchun qulfdan chiqaring"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Tarmoqlar qidirilmoqda…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Tarmoqqa ulanmadi"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi hozir avtomatik ulanmaydi"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Hammasi"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Boshqa tarmoqqa almashish uchun Ethernet tarmogʻini uzing"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index d046494e2134..b0f1dcf31133 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Mở khóa để xem mạng"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Đang tìm mạng…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Không kết nối được với mạng"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Tạm thời, Wi-Fi sẽ không tự động kết nối"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Xem tất cả"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Để chuyển mạng, hãy rút cáp Ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index c7747fac198e..7caae5df46e5 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"解锁即可查看网络"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜索网络…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"未能连接到网络"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WLAN 暂时无法自动连接"</string>
<string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切换网络,请断开以太网连接"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index e7ffeeae336e..4a8567d7d29b 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"解鎖即可查看網絡"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜尋網絡…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"無法連接網絡"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"目前系統不會自動連線至 Wi-Fi"</string>
<string name="see_all_networks" msgid="3773666844913168122">"顯示全部"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切換網絡,請中斷以太網連線"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index b49cd2b1e7cc..b444d4223b7f 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"解鎖螢幕即可查看網路"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜尋網路…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"無法連上網路"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"目前不會自動連上 Wi-Fi"</string>
<string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切換網路,請中斷乙太網路連線"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index d4fb489807cb..79884764562a 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -1175,6 +1175,7 @@
<string name="unlock_to_view_networks" msgid="5072880496312015676">"Vula ukuze ubuke amanethiwekhi"</string>
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Iseshela amanethiwekhi…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Yehlulekile ukuxhuma kunethiwekhi"</string>
+ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"I-Wi-Fi ngeke ixhume ngokuzenzakalelayo okwamanje"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Bona konke"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ukuze ushintshe amanethiwekhi, nqamula i-ethernet"</string>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 08778bf14c66..03c6fddb145c 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -70,7 +70,7 @@
<color name="keyguard_shadow_color">#B2000000</color>
<!-- Color for the images in keyguard number pad buttons -->
- <color name="keyguard_keypad_image_color">@android:color/background_light</color>
+ <color name="keyguard_keypad_image_color">?android:attr/textColorPrimaryInverse</color>
<!-- Color for rounded background for activated user in keyguard user switcher -->
<color name="kg_user_switcher_activated_background_color">#26000000</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 70149267e3dd..8650654ea288 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1596,7 +1596,9 @@
<!-- Internet panel related dimensions -->
<dimen name="internet_dialog_list_margin">12dp</dimen>
<dimen name="internet_dialog_list_max_height">646dp</dimen>
- <dimen name="internet_dialog_list_max_width">@dimen/match_parent</dimen>
+
+ <!-- The width of large/content heavy dialogs (e.g. Internet, Media output, etc) -->
+ <dimen name="large_dialog_width">@dimen/match_parent</dimen>
<!-- Signal icon in internet dialog -->
<dimen name="signal_strength_icon_size">24dp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 93d60cce2915..6594216e4290 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -331,9 +331,6 @@
<style name="Animation.ShutdownUi" parent="@android:style/Animation.Toast">
</style>
- <style name="Animation.MediaOutputDialog" parent="@android:style/Animation.InputMethod">
- </style>
-
<!-- Standard animations for hiding and showing the status bar. -->
<style name="Animation.StatusBar">
</style>
@@ -436,10 +433,6 @@
<item name="android:windowCloseOnTouchOutside">true</item>
</style>
- <style name="Theme.SystemUI.Dialog.MediaOutput">
- <item name="android:windowBackground">@drawable/media_output_dialog_background</item>
- </style>
-
<style name="QSBorderlessButton">
<item name="android:padding">12dp</item>
<item name="android:background">@drawable/qs_btn_borderless_rect</item>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index 92f8454fc93e..0529cdbcbb13 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -208,8 +208,7 @@ public class KeyguardPasswordViewController
mView.post(() -> {
if (mView.isShown()) {
mPasswordEntry.requestFocus();
- mInputMethodManager.showSoftInput(
- mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
+ mPasswordEntry.getWindowInsetsController().show(WindowInsets.Type.ime());
}
});
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index c659bf786a45..f4ce643a085c 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -18,6 +18,7 @@ package com.android.keyguard;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
+import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.graphics.drawable.VectorDrawable;
@@ -26,8 +27,6 @@ import android.view.MotionEvent;
import androidx.annotation.Nullable;
-import com.android.systemui.R;
-
/**
* Similar to the {@link NumPadKey}, but displays an image.
*/
@@ -92,7 +91,10 @@ public class NumPadButton extends AlphaOptimizedImageButton {
public void reloadColors() {
if (mAnimator != null) mAnimator.reloadColors(getContext());
- int imageColor = getContext().getColor(R.color.keyguard_keypad_image_color);
+ int[] customAttrs = {android.R.attr.textColorPrimaryInverse};
+ TypedArray a = getContext().obtainStyledAttributes(customAttrs);
+ int imageColor = a.getColor(0, 0);
+ a.recycle();
((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(imageColor));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index e7445f920ffe..424f80177d9c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -364,9 +364,9 @@ public class MediaControlPanel {
seamlessView.setVisibility(View.VISIBLE);
setVisibleAndAlpha(collapsedSet, R.id.media_seamless, true /*visible */);
setVisibleAndAlpha(expandedSet, R.id.media_seamless, true /*visible */);
- seamlessView.setOnClickListener(v -> {
- mMediaOutputDialogFactory.create(data.getPackageName(), true);
- });
+ seamlessView.setOnClickListener(
+ v -> mMediaOutputDialogFactory.create(data.getPackageName(), true,
+ mPlayerViewHolder.getSeamlessButton()));
ImageView iconView = mPlayerViewHolder.getSeamlessIcon();
TextView deviceName = mPlayerViewHolder.getSeamlessText();
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index 35603b6ef6cc..f32dad632721 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -43,6 +43,7 @@ class PlayerViewHolder private constructor(itemView: View) {
val seamless = itemView.requireViewById<ViewGroup>(R.id.media_seamless)
val seamlessIcon = itemView.requireViewById<ImageView>(R.id.media_seamless_image)
val seamlessText = itemView.requireViewById<TextView>(R.id.media_seamless_text)
+ val seamlessButton = itemView.requireViewById<View>(R.id.media_seamless_button)
// Seek bar
val seekBar = itemView.requireViewById<SeekBar>(R.id.media_progress_bar)
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 391dff634dab..d1b6548132a6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -45,11 +45,14 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
private static final String TAG = "MediaOutputAdapter";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private final MediaOutputDialog mMediaOutputDialog;
private ViewGroup mConnectedItem;
private boolean mIncludeDynamicGroup;
- public MediaOutputAdapter(MediaOutputController controller) {
+ public MediaOutputAdapter(MediaOutputController controller,
+ MediaOutputDialog mediaOutputDialog) {
super(controller);
+ mMediaOutputDialog = mediaOutputDialog;
}
@Override
@@ -136,7 +139,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mDivider.setTransitionAlpha(1);
mAddIcon.setVisibility(View.VISIBLE);
mAddIcon.setTransitionAlpha(1);
- mAddIcon.setOnClickListener(v -> onEndItemClick());
+ mAddIcon.setOnClickListener(this::onEndItemClick);
} else {
// Init non-active device layout
mDivider.setVisibility(View.GONE);
@@ -197,7 +200,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mDivider.setTransitionAlpha(1);
mAddIcon.setVisibility(View.VISIBLE);
mAddIcon.setTransitionAlpha(1);
- mAddIcon.setOnClickListener(v -> onEndItemClick());
+ mAddIcon.setOnClickListener(this::onEndItemClick);
} else {
mDivider.setVisibility(View.GONE);
mAddIcon.setVisibility(View.GONE);
@@ -232,8 +235,8 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
}
}
- private void onEndItemClick() {
- mController.launchMediaOutputGroupDialog();
+ private void onEndItemClick(View view) {
+ mController.launchMediaOutputGroupDialog(mMediaOutputDialog.getDialogView());
}
}
}
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 cdcdf9a1d4de..85d0802012ac 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -82,7 +82,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
};
public MediaOutputBaseDialog(Context context, MediaOutputController mediaOutputController) {
- super(context, R.style.Theme_SystemUI_Dialog_MediaOutput);
+ super(context);
mContext = context;
mMediaOutputController = mediaOutputController;
mLayoutManager = new LinearLayoutManager(mContext);
@@ -97,15 +97,15 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
mDialogView = LayoutInflater.from(mContext).inflate(R.layout.media_output_dialog, null);
final Window window = getWindow();
final WindowManager.LayoutParams lp = window.getAttributes();
- lp.gravity = Gravity.BOTTOM;
+ lp.gravity = Gravity.CENTER;
// Config insets to make sure the layout is above the navigation bar
lp.setFitInsetsTypes(statusBars() | navigationBars());
lp.setFitInsetsSides(WindowInsets.Side.all());
lp.setFitInsetsIgnoringVisibility(true);
window.setAttributes(lp);
window.setContentView(mDialogView);
- window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- window.setWindowAnimations(R.style.Animation_MediaOutputDialog);
+ window.setLayout(mContext.getResources().getDimensionPixelSize(R.dimen.large_dialog_width),
+ ViewGroup.LayoutParams.WRAP_CONTENT);
mHeaderTitle = mDialogView.requireViewById(R.id.header_title);
mHeaderSubtitle = mDialogView.requireViewById(R.id.header_subtitle);
@@ -229,4 +229,8 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
void onHeaderIconClick() {
}
+
+ View getDialogView() {
+ return mDialogView;
+ }
}
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 b2def7a8596a..437a0c85a6e0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -32,6 +32,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.Log;
+import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -48,6 +49,7 @@ import com.android.settingslib.media.MediaDevice;
import com.android.settingslib.media.MediaOutputConstants;
import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.R;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -73,6 +75,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
private final MediaSessionManager mMediaSessionManager;
private final ShadeController mShadeController;
private final ActivityStarter mActivityStarter;
+ private final DialogLaunchAnimator mDialogLaunchAnimator;
private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
private final boolean mAboveStatusbar;
private final NotificationEntryManager mNotificationEntryManager;
@@ -82,6 +85,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
private MediaController mMediaController;
@VisibleForTesting
Callback mCallback;
+ Callback mPreviousCallback;
@VisibleForTesting
LocalMediaManager mLocalMediaManager;
@@ -92,7 +96,8 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
public MediaOutputController(@NonNull Context context, String packageName,
boolean aboveStatusbar, MediaSessionManager mediaSessionManager, LocalBluetoothManager
lbm, ShadeController shadeController, ActivityStarter starter,
- NotificationEntryManager notificationEntryManager, UiEventLogger uiEventLogger) {
+ NotificationEntryManager notificationEntryManager, UiEventLogger uiEventLogger,
+ DialogLaunchAnimator dialogLaunchAnimator) {
mContext = context;
mPackageName = packageName;
mMediaSessionManager = mediaSessionManager;
@@ -104,6 +109,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName);
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
mUiEventLogger = uiEventLogger;
+ mDialogLaunchAnimator = dialogLaunchAnimator;
}
void start(@NonNull Callback cb) {
@@ -129,7 +135,19 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
}
return;
}
+
+ if (mPreviousCallback != null) {
+ Log.w(TAG,
+ "Callback started when mPreviousCallback is not null, which is unexpected");
+ mPreviousCallback.dismissDialog();
+ }
+
+ // If we start the output group dialog when the output dialog is shown, we need to keep a
+ // reference to the output dialog to set it back as the callback once we dismiss the output
+ // group dialog.
+ mPreviousCallback = mCallback;
mCallback = cb;
+
mLocalMediaManager.unregisterCallback(this);
mLocalMediaManager.stopScan();
mLocalMediaManager.registerCallback(this);
@@ -145,6 +163,15 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
mLocalMediaManager.stopScan();
}
mMediaDevices.clear();
+
+ // If there was a previous callback, i.e. we just dismissed the output group dialog and are
+ // now back on the output dialog, then we reset the callback to its previous value.
+ mCallback = null;
+ Callback previous = mPreviousCallback;
+ mPreviousCallback = null;
+ if (previous != null) {
+ start(previous);
+ }
}
@Override
@@ -436,6 +463,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
}
void launchBluetoothPairing() {
+ // Dismissing a dialog into its touch surface and starting an activity at the same time
+ // looks bad, so let's make sure the dialog just fades out quickly.
+ mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
+
mCallback.dismissDialog();
final ActivityStarter.OnDismissAction postKeyguardAction = () -> {
mContext.sendBroadcast(new Intent()
@@ -447,14 +478,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
mActivityStarter.dismissKeyguardThenExecute(postKeyguardAction, null, true);
}
- void launchMediaOutputDialog() {
- mCallback.dismissDialog();
- new MediaOutputDialog(mContext, mAboveStatusbar, this, mUiEventLogger);
- }
-
- void launchMediaOutputGroupDialog() {
- mCallback.dismissDialog();
- new MediaOutputGroupDialog(mContext, mAboveStatusbar, this);
+ void launchMediaOutputGroupDialog(View mediaOutputDialog) {
+ // We show the output group dialog from the output dialog.
+ MediaOutputGroupDialog dialog = new MediaOutputGroupDialog(mContext, mAboveStatusbar, this);
+ mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);
}
boolean isActiveRemoteDevice(@NonNull MediaDevice device) {
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 53029bd04ef6..eca8ac90427b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -40,11 +40,10 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
mediaOutputController, UiEventLogger uiEventLogger) {
super(context, mediaOutputController);
mUiEventLogger = uiEventLogger;
- mAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mAdapter = new MediaOutputAdapter(mMediaOutputController, this);
if (!aboveStatusbar) {
getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
}
- show();
}
@Override
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 0f340a5cedaa..b91901de5af3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -18,8 +18,10 @@ package com.android.systemui.media.dialog
import android.content.Context
import android.media.session.MediaSessionManager
+import android.view.View
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.bluetooth.LocalBluetoothManager
+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
@@ -35,19 +37,29 @@ class MediaOutputDialogFactory @Inject constructor(
private val shadeController: ShadeController,
private val starter: ActivityStarter,
private val notificationEntryManager: NotificationEntryManager,
- private val uiEventLogger: UiEventLogger
+ private val uiEventLogger: UiEventLogger,
+ private val dialogLaunchAnimator: DialogLaunchAnimator
) {
companion object {
var mediaOutputDialog: MediaOutputDialog? = null
}
/** Creates a [MediaOutputDialog] for the given package. */
- fun create(packageName: String, aboveStatusBar: Boolean) {
+ fun create(packageName: String, aboveStatusBar: Boolean, view: View? = null) {
+ // Dismiss the previous dialog, if any.
mediaOutputDialog?.dismiss()
- mediaOutputDialog = MediaOutputController(context, packageName, aboveStatusBar,
- mediaSessionManager, lbm, shadeController, starter, notificationEntryManager,
- uiEventLogger).run {
- MediaOutputDialog(context, aboveStatusBar, this, uiEventLogger)
+
+ val controller = MediaOutputController(context, packageName, aboveStatusBar,
+ mediaSessionManager, lbm, shadeController, starter, notificationEntryManager,
+ uiEventLogger, dialogLaunchAnimator)
+ val dialog = MediaOutputDialog(context, aboveStatusBar, controller, uiEventLogger)
+ mediaOutputDialog = dialog
+
+ // Show the dialog.
+ if (view != null) {
+ dialogLaunchAnimator.showFromView(dialog, view)
+ } else {
+ dialog.show()
}
}
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 407930492fbe..1300400f3b66 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
@@ -38,7 +38,6 @@ public class MediaOutputGroupDialog extends MediaOutputBaseDialog {
if (!aboveStatusbar) {
getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
}
- show();
}
@Override
@@ -83,6 +82,8 @@ public class MediaOutputGroupDialog extends MediaOutputBaseDialog {
@Override
void onHeaderIconClick() {
- mMediaOutputController.launchMediaOutputDialog();
+ // Given that we launched the media output group dialog from the media output dialog,
+ // dismissing this dialog will show the media output dialog again.
+ dismiss();
}
}
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 dc54e1b52f2e..11430d93106a 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
@@ -206,7 +206,7 @@ public class InternetDialog extends SystemUIDialog implements
window.setContentView(mDialogView);
//Only fix the width for large screen or tablet.
window.setLayout(mContext.getResources().getDimensionPixelSize(
- R.dimen.internet_dialog_list_max_width), ViewGroup.LayoutParams.WRAP_CONTENT);
+ R.dimen.large_dialog_width), ViewGroup.LayoutParams.WRAP_CONTENT);
window.setWindowAnimations(R.style.Animation_InternetDialog);
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
window.addFlags(FLAG_LAYOUT_NO_LIMITS);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 17bcfe73ccd9..8a397199dc84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -335,7 +335,7 @@ public class KeyguardIndicationController {
info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
}
}
- if (info != null) {
+ if (!TextUtils.isEmpty(info)) {
mRotateTextViewController.updateIndication(
INDICATION_TYPE_OWNER_INFO,
new KeyguardIndication.Builder()
@@ -433,7 +433,7 @@ public class KeyguardIndicationController {
}
private void updateResting() {
- if (mRestingIndication != null
+ if (!TextUtils.isEmpty(mRestingIndication)
&& !mRotateTextViewController.hasIndications()) {
mRotateTextViewController.updateIndication(
INDICATION_TYPE_RESTING,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index 94f186f00778..ea00d920c9b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -22,6 +22,9 @@ import android.content.Context;
import android.os.Handler;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
@@ -62,6 +65,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
+import com.android.systemui.statusbar.phone.SystemUIHostDialogProvider;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLogger;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
@@ -261,4 +265,29 @@ public interface StatusBarDependenciesModule {
@Binds
QSCarrierGroupController.SlotIndexResolver provideSlotIndexResolver(
QSCarrierGroupController.SubscriptionManagerSlotIndexResolver impl);
+
+ /**
+ */
+ @Provides
+ @SysUISingleton
+ static LaunchAnimator provideLaunchAnimator(Context context) {
+ return new LaunchAnimator(context);
+ }
+
+ /**
+ */
+ @Provides
+ @SysUISingleton
+ static ActivityLaunchAnimator provideActivityLaunchAnimator(LaunchAnimator launchAnimator) {
+ return new ActivityLaunchAnimator(launchAnimator);
+ }
+
+ /**
+ */
+ @Provides
+ @SysUISingleton
+ static DialogLaunchAnimator provideDialogLaunchAnimator(Context context,
+ LaunchAnimator launchAnimator) {
+ return new DialogLaunchAnimator(context, launchAnimator, new SystemUIHostDialogProvider());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index d7f32251e3d9..a76389b1bbc8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -24,7 +24,6 @@ import android.app.smartspace.SmartspaceTarget
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
-import android.content.pm.UserInfo
import android.database.ContentObserver
import android.net.Uri
import android.os.Handler
@@ -193,7 +192,7 @@ class LockscreenSmartspaceController @Inject constructor(
}
private fun connectSession() {
- if (plugin == null || session != null) {
+ if (plugin == null || session != null || smartspaceViews.isEmpty()) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt
index f19cf5d8d9c7..64a73054c434 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt
@@ -2,8 +2,8 @@ package com.android.systemui.statusbar.notification
import android.util.MathUtils
import com.android.internal.annotations.VisibleForTesting
-import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.animation.Interpolators
+import com.android.systemui.animation.LaunchAnimator
import kotlin.math.min
/** Parameters for the notifications expand animations. */
@@ -15,7 +15,7 @@ class ExpandAnimationParameters(
topCornerRadius: Float = 0f,
bottomCornerRadius: Float = 0f
-) : ActivityLaunchAnimator.State(top, bottom, left, right, topCornerRadius, bottomCornerRadius) {
+) : LaunchAnimator.State(top, bottom, left, right, topCornerRadius, bottomCornerRadius) {
@VisibleForTesting
constructor() : this(
top = 0, bottom = 0, left = 0, right = 0, topCornerRadius = 0f, bottomCornerRadius = 0f
@@ -55,6 +55,6 @@ class ExpandAnimationParameters(
}
fun getProgress(delay: Long, duration: Long): Float {
- return ActivityLaunchAnimator.getProgress(linearProgress, delay, duration)
+ return LaunchAnimator.getProgress(linearProgress, delay, duration)
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index 1bbef2562d21..22c3eda03b1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -3,6 +3,7 @@ package com.android.systemui.statusbar.notification
import android.view.ViewGroup
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.LaunchAnimator
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
@@ -54,7 +55,7 @@ class NotificationLaunchAnimatorController(
// Do nothing. Notifications are always animated inside their rootView.
}
- override fun createAnimatorState(): ActivityLaunchAnimator.State {
+ override fun createAnimatorState(): LaunchAnimator.State {
// If the notification panel is collapsed, the clip may be larger than the height.
val height = max(0, notification.actualHeight - notification.clipBottomAmount)
val location = notification.locationOnScreen
@@ -72,12 +73,12 @@ class NotificationLaunchAnimatorController(
notification.currentBackgroundRadiusTop
}
val params = ExpandAnimationParameters(
- top = windowTop,
- bottom = location[1] + height,
- left = location[0],
- right = location[0] + notification.width,
- topCornerRadius = topCornerRadius,
- bottomCornerRadius = notification.currentBackgroundRadiusBottom
+ top = windowTop,
+ bottom = location[1] + height,
+ left = location[0],
+ right = location[0] + notification.width,
+ topCornerRadius = topCornerRadius,
+ bottomCornerRadius = notification.currentBackgroundRadiusBottom
)
params.startTranslationZ = notification.translationZ
@@ -86,8 +87,8 @@ class NotificationLaunchAnimatorController(
params.startClipTopAmount = notification.clipTopAmount
if (notification.isChildInGroup) {
params.startNotificationTop += notification.notificationParent.translationY
- val parentRoundedClip = Math.max(clipStartLocation
- - notification.notificationParent.locationOnScreen[1], 0)
+ val parentRoundedClip = Math.max(
+ clipStartLocation - notification.notificationParent.locationOnScreen[1], 0)
params.parentStartRoundedTopClipping = parentRoundedClip
val parentClip = notification.notificationParent.clipTopAmount
@@ -157,7 +158,7 @@ class NotificationLaunchAnimatorController(
}
override fun onLaunchAnimationProgress(
- state: ActivityLaunchAnimator.State,
+ state: LaunchAnimator.State,
progress: Float,
linearProgress: Float
) {
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 9018cef72f7d..6d6cb7dcc693 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -103,8 +103,8 @@ import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
@@ -212,7 +212,7 @@ public class NotificationPanelViewController extends PanelViewController {
*/
private static final int FLING_HIDE = 2;
private static final long ANIMATION_DELAY_ICON_FADE_IN =
- ActivityLaunchAnimator.ANIMATION_DURATION - CollapsedStatusBarFragment.FADE_IN_DURATION
+ LaunchAnimator.ANIMATION_DURATION - CollapsedStatusBarFragment.FADE_IN_DURATION
- CollapsedStatusBarFragment.FADE_IN_DELAY - 48;
private final DozeParameters mDozeParameters;
@@ -3594,7 +3594,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
public void applyLaunchAnimationProgress(float linearProgress) {
- boolean hideIcons = ActivityLaunchAnimator.getProgress(linearProgress,
+ boolean hideIcons = LaunchAnimator.getProgress(linearProgress,
ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f;
if (hideIcons != mHideIconsDuringLaunchAnimation) {
mHideIconsDuringLaunchAnimation = hideIcons;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index ee7725f670b0..e104aef2e8b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -135,6 +135,7 @@ import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DelegateLaunchAnimatorController;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.biometrics.AuthRippleController;
@@ -669,7 +670,8 @@ public class StatusBar extends SystemUI implements
private final SysuiStatusBarStateController mStatusBarStateController;
private HeadsUpAppearanceController mHeadsUpAppearanceController;
- private ActivityLaunchAnimator mActivityLaunchAnimator;
+ private final ActivityLaunchAnimator mActivityLaunchAnimator;
+ private final DialogLaunchAnimator mDialogLaunchAnimator;
private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
protected StatusBarNotificationPresenter mPresenter;
private NotificationActivityStarter mNotificationActivityStarter;
@@ -792,7 +794,9 @@ public class StatusBar extends SystemUI implements
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
Optional<StartingSurface> startingSurfaceOptional,
TunerService tunerService,
- DumpManager dumpManager) {
+ DumpManager dumpManager,
+ ActivityLaunchAnimator activityLaunchAnimator,
+ DialogLaunchAnimator dialogLaunchAnimator) {
super(context);
mNotificationsController = notificationsController;
mLightBarController = lightBarController;
@@ -900,6 +904,8 @@ public class StatusBar extends SystemUI implements
});
mActivityIntentHelper = new ActivityIntentHelper(mContext);
+ mActivityLaunchAnimator = activityLaunchAnimator;
+ mDialogLaunchAnimator = dialogLaunchAnimator;
// TODO(b/190746471): Find a better home for this.
DateTimeView.setReceiverHandler(timeTickHandler);
@@ -1467,7 +1473,7 @@ public class StatusBar extends SystemUI implements
private void setUpPresenter() {
// Set up the initial notification state.
- mActivityLaunchAnimator = new ActivityLaunchAnimator(mKeyguardHandler, mContext);
+ mActivityLaunchAnimator.setCallback(mKeyguardHandler);
mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider(
mNotificationShadeWindowViewController,
mStackScrollerController.getNotificationListContainer(),
@@ -2549,7 +2555,8 @@ public class StatusBar extends SystemUI implements
animationController != null && !willLaunchResolverActivity && shouldAnimateLaunch(
true /* isActivityIntent */);
ActivityLaunchAnimator.Controller animController =
- animate ? wrapAnimationController(animationController, dismissShade) : null;
+ animationController != null ? wrapAnimationController(animationController,
+ dismissShade) : null;
// If we animate, we will dismiss the shade only once the animation is done. This is taken
// care of by the StatusBarLaunchAnimationController.
@@ -4426,6 +4433,8 @@ public class StatusBar extends SystemUI implements
&& !mBiometricUnlockController.isWakeAndUnlock()) {
mLightRevealScrim.setRevealAmount(1f - linear);
}
+
+ mDialogLaunchAnimator.onDozeAmountChanged(linear);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 77254435b688..5bc97a5b316d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -53,6 +53,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
@@ -94,7 +95,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
// with the appear animations of the PIN/pattern/password views.
private static final long NAV_BAR_SHOW_DELAY_BOUNCER = 320;
- private static final long WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS = 200;
+ // The duration to fade the nav bar content in/out when the device starts to sleep
+ private static final long NAV_BAR_CONTENT_FADE_DURATION = 125;
// Duration of the Keyguard dismissal animation in case the user is currently locked. This is to
// make everything a bit slower to bridge a gap until the user is unlocked and home screen has
@@ -197,10 +199,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private boolean mLastGesturalNav;
private boolean mLastIsDocked;
private boolean mLastPulsing;
- private boolean mLastAnimatedToSleep;
private int mLastBiometricMode;
private boolean mQsExpanded;
- private boolean mAnimatedToSleep;
private OnDismissAction mAfterKeyguardGoneAction;
private Runnable mKeyguardGoneCancelAction;
@@ -325,20 +325,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mDockManager.addListener(mDockEventListener);
mIsDocked = mDockManager.isDocked();
}
- mWakefulnessLifecycle.addObserver(new WakefulnessLifecycle.Observer() {
- @Override
- public void onFinishedWakingUp() {
- mAnimatedToSleep = false;
- updateStates();
- }
-
- @Override
- public void onFinishedGoingToSleep() {
- mAnimatedToSleep =
- mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying();
- updateStates();
- }
- });
}
@Override
@@ -571,12 +557,26 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
public void onStartedWakingUp() {
mStatusBar.getNotificationShadeWindowView().getWindowInsetsController()
.setAnimationsDisabled(false);
+ View currentView = getCurrentNavBarView();
+ if (currentView != null) {
+ currentView.animate()
+ .alpha(1f)
+ .setDuration(NAV_BAR_CONTENT_FADE_DURATION)
+ .start();
+ }
}
@Override
public void onStartedGoingToSleep() {
mStatusBar.getNotificationShadeWindowView().getWindowInsetsController()
.setAnimationsDisabled(true);
+ View currentView = getCurrentNavBarView();
+ if (currentView != null) {
+ currentView.animate()
+ .alpha(0f)
+ .setDuration(NAV_BAR_CONTENT_FADE_DURATION)
+ .start();
+ }
}
@Override
@@ -1013,10 +1013,28 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mLastBiometricMode = mBiometricUnlockController.getMode();
mLastGesturalNav = mGesturalNav;
mLastIsDocked = mIsDocked;
- mLastAnimatedToSleep = mAnimatedToSleep;
mStatusBar.onKeyguardViewManagerStatesUpdated();
}
+ /**
+ * Updates the visibility of the nav bar content views.
+ */
+ private void updateNavigationBarContentVisibility(boolean navBarContentVisible) {
+ final NavigationBarView navBarView = mStatusBar.getNavigationBarView();
+ if (navBarView != null && navBarView.getCurrentView() != null) {
+ final View currentView = navBarView.getCurrentView();
+ currentView.setVisibility(navBarContentVisible ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+
+ private View getCurrentNavBarView() {
+ final NavigationBarView navBarView = mStatusBar.getNavigationBarView();
+ return navBarView != null ? navBarView.getCurrentView() : null;
+ }
+
+ /**
+ * Updates the visibility of the nav bar window (which will cause insets changes).
+ */
protected void updateNavigationBarVisibility(boolean navBarVisible) {
if (mStatusBar.getNavigationBarView() != null) {
if (navBarVisible) {
@@ -1044,7 +1062,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
boolean hideWhileDozing = mDozing && biometricMode != MODE_WAKE_AND_UNLOCK_PULSING;
boolean keyguardWithGestureNav = (keyguardShowing && !mDozing || mPulsing && !mIsDocked)
&& mGesturalNav;
- return (!mAnimatedToSleep && !keyguardShowing && !hideWhileDozing || mBouncer.isShowing()
+ return (!keyguardShowing && !hideWhileDozing || mBouncer.isShowing()
|| mRemoteInputActive || keyguardWithGestureNav
|| mGlobalActionsVisible);
}
@@ -1057,7 +1075,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
boolean hideWhileDozing = mLastDozing && mLastBiometricMode != MODE_WAKE_AND_UNLOCK_PULSING;
boolean keyguardWithGestureNav = (keyguardShowing && !mLastDozing
|| mLastPulsing && !mLastIsDocked) && mLastGesturalNav;
- return (!mLastAnimatedToSleep && !keyguardShowing && !hideWhileDozing || mLastBouncerShowing
+ return (!keyguardShowing && !hideWhileDozing || mLastBouncerShowing
|| mLastRemoteInputActive || keyguardWithGestureNav
|| mLastGlobalActionsVisible);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
index 14e513a0556d..32aae6c05df6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
@@ -1,6 +1,7 @@
package com.android.systemui.statusbar.phone
import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.LaunchAnimator
/**
* A [ActivityLaunchAnimator.Controller] that takes care of collapsing the status bar at the right
@@ -22,7 +23,7 @@ class StatusBarLaunchAnimatorController(
delegate.onLaunchAnimationStart(isExpandingFullyAbove)
statusBar.notificationPanelViewController.setIsLaunchAnimationRunning(true)
if (!isExpandingFullyAbove) {
- statusBar.collapsePanelWithDuration(ActivityLaunchAnimator.ANIMATION_DURATION.toInt())
+ statusBar.collapsePanelWithDuration(LaunchAnimator.ANIMATION_DURATION.toInt())
}
}
@@ -33,7 +34,7 @@ class StatusBarLaunchAnimatorController(
}
override fun onLaunchAnimationProgress(
- state: ActivityLaunchAnimator.State,
+ state: LaunchAnimator.State,
progress: Float,
linearProgress: Float
) {
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 1e98c75f2616..9415d5082d10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -30,19 +30,24 @@ import android.view.WindowManager.LayoutParams;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.animation.DialogListener;
+import com.android.systemui.animation.ListenableDialog;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
/**
* Base class for dialogs that should appear over panels and keyguard.
* The SystemUIDialog registers a listener for the screen off / close system dialogs broadcast,
* and dismisses itself when it receives the broadcast.
*/
-public class SystemUIDialog extends AlertDialog {
-
+public class SystemUIDialog extends AlertDialog implements ListenableDialog {
private final Context mContext;
private final DismissReceiver mDismissReceiver;
+ private final Set<DialogListener> mDialogListeners = new LinkedHashSet<>();
public SystemUIDialog(Context context) {
this(context, R.style.Theme_SystemUI_Dialog);
@@ -72,6 +77,43 @@ public class SystemUIDialog extends AlertDialog {
mDismissReceiver.unregister();
}
+ @Override
+ public void addListener(DialogListener listener) {
+ mDialogListeners.add(listener);
+ }
+
+ @Override
+ public void removeListener(DialogListener listener) {
+ mDialogListeners.remove(listener);
+ }
+
+ @Override
+ public void dismiss() {
+ super.dismiss();
+
+ for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) {
+ listener.onDismiss();
+ }
+ }
+
+ @Override
+ public void hide() {
+ super.hide();
+
+ for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) {
+ listener.onHide();
+ }
+ }
+
+ @Override
+ public void show() {
+ super.show();
+
+ for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) {
+ listener.onShow();
+ }
+ }
+
public void setShowForAllUsers(boolean show) {
setShowForAllUsers(this, show);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt
new file mode 100644
index 000000000000..6a49a6da0d62
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt
@@ -0,0 +1,36 @@
+package com.android.systemui.statusbar.phone
+
+import android.app.Dialog
+import android.content.Context
+import android.os.Bundle
+import com.android.systemui.animation.HostDialogProvider
+
+/** An implementation of [HostDialogProvider] to be used when animating SysUI dialogs. */
+class SystemUIHostDialogProvider : HostDialogProvider {
+ override fun createHostDialog(
+ context: Context,
+ theme: Int,
+ onCreateCallback: () -> Unit,
+ dismissOverride: (() -> Unit) -> Unit
+ ): Dialog {
+ return SystemUIHostDialog(context, theme, onCreateCallback, dismissOverride)
+ }
+
+ private class SystemUIHostDialog(
+ context: Context,
+ theme: Int,
+ private val onCreateCallback: () -> Unit,
+ private val dismissOverride: (() -> Unit) -> Unit
+ ) : SystemUIDialog(context, theme) {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ onCreateCallback()
+ }
+
+ override fun dismiss() {
+ dismissOverride {
+ super.dismiss()
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 13eb75a4d508..0d43b9323a39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -28,6 +28,8 @@ import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.InitController;
+import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector;
@@ -235,7 +237,9 @@ public interface StatusBarPhoneModule {
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
Optional<StartingSurface> startingSurfaceOptional,
TunerService tunerService,
- DumpManager dumpManager) {
+ DumpManager dumpManager,
+ ActivityLaunchAnimator activityLaunchAnimator,
+ DialogLaunchAnimator dialogLaunchAnimator) {
return new StatusBar(
context,
notificationsController,
@@ -333,6 +337,8 @@ public interface StatusBarPhoneModule {
unlockedScreenOffAnimationController,
startingSurfaceOptional,
tunerService,
- dumpManager);
+ dumpManager,
+ activityLaunchAnimator,
+ dialogLaunchAnimator);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt
index db2aca873d0c..a9810458fe90 100644
--- a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt
@@ -40,8 +40,8 @@ class WallpaperController @Inject constructor(private val wallpaperManager: Wall
this.wallpaperInfo = wallpaperInfo
}
- private val shouldUseDefaultUnfoldTransition: Boolean
- get() = wallpaperInfo?.shouldUseDefaultUnfoldTransition()
+ private val shouldUseDefaultDeviceStateChangeTransition: Boolean
+ get() = wallpaperInfo?.shouldUseDefaultDeviceStateChangeTransition()
?: true
fun setNotificationShadeZoom(zoomOut: Float) {
@@ -50,7 +50,7 @@ class WallpaperController @Inject constructor(private val wallpaperManager: Wall
}
fun setUnfoldTransitionZoom(zoomOut: Float) {
- if (shouldUseDefaultUnfoldTransition) {
+ if (shouldUseDefaultDeviceStateChangeTransition) {
unfoldTransitionZoomOut = zoomOut
updateZoom()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
index cc35a8f9e1b5..d819fa2adc38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
@@ -46,6 +46,7 @@ import org.mockito.junit.MockitoJUnit
@RunWithLooper
class ActivityLaunchAnimatorTest : SysuiTestCase() {
private val launchContainer = LinearLayout(mContext)
+ private val launchAnimator = LaunchAnimator(mContext, isForTesting = true)
@Mock lateinit var callback: ActivityLaunchAnimator.Callback
@Spy private val controller = TestLaunchAnimatorController(launchContainer)
@Mock lateinit var iCallback: IRemoteAnimationFinishedCallback
@@ -56,7 +57,8 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
@Before
fun setup() {
- activityLaunchAnimator = ActivityLaunchAnimator(callback, mContext)
+ activityLaunchAnimator = ActivityLaunchAnimator(launchAnimator)
+ activityLaunchAnimator.callback = callback
}
private fun startIntentWithAnimation(
@@ -120,7 +122,8 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
@Test
fun animatesIfActivityIsAlreadyOpenAndIsOnKeyguard() {
`when`(callback.isOnKeyguard()).thenReturn(true)
- val animator = ActivityLaunchAnimator(callback, context)
+ val animator = ActivityLaunchAnimator(launchAnimator)
+ animator.callback = callback
val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java)
var animationAdapter: RemoteAnimationAdapter? = null
@@ -208,7 +211,7 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
private class TestLaunchAnimatorController(
override var launchContainer: ViewGroup
) : ActivityLaunchAnimator.Controller {
- override fun createAnimatorState() = ActivityLaunchAnimator.State(
+ override fun createAnimatorState() = LaunchAnimator.State(
top = 100,
bottom = 200,
left = 300,
@@ -232,7 +235,7 @@ private class TestLaunchAnimatorController(
}
override fun onLaunchAnimationProgress(
- state: ActivityLaunchAnimator.State,
+ state: LaunchAnimator.State,
progress: Float,
linearProgress: Float
) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
new file mode 100644
index 000000000000..5bcf828afe9f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
@@ -0,0 +1,186 @@
+package com.android.systemui.animation
+
+import android.app.Dialog
+import android.content.Context
+import android.os.Bundle
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.ViewUtils
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+import android.widget.LinearLayout
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class DialogLaunchAnimatorTest : SysuiTestCase() {
+ private val launchAnimator = LaunchAnimator(context, isForTesting = true)
+ private val hostDialogprovider = TestHostDialogProvider()
+ private val dialogLaunchAnimator =
+ DialogLaunchAnimator(context, launchAnimator, hostDialogprovider)
+
+ @Test
+ fun testShowDialogFromView() {
+ // Show the dialog. showFromView() must be called on the main thread with a dialog created
+ // on the main thread too.
+ val (dialog, hostDialog) = runOnMainThreadAndWaitForIdleSync {
+ val touchSurfaceRoot = LinearLayout(context)
+ val touchSurface = View(context)
+ touchSurfaceRoot.addView(touchSurface)
+
+ // We need to attach the root to the window manager otherwise the exit animation will
+ // be skipped
+ ViewUtils.attachView(touchSurfaceRoot)
+
+ val dialog = TestDialog(context)
+ val hostDialog =
+ dialogLaunchAnimator.showFromView(dialog, touchSurface) as TestHostDialog
+ dialog to hostDialog
+ }
+
+ // Only the host dialog is actually showing.
+ assertTrue(hostDialog.isShowing)
+ assertFalse(dialog.isShowing)
+
+ // The dialog onStart() method was called but not onStop().
+ assertTrue(dialog.onStartCalled)
+ assertFalse(dialog.onStopCalled)
+
+ // The dialog content has been stolen and is shown inside the host dialog.
+ val hostDialogContent = hostDialog.findViewById<ViewGroup>(android.R.id.content)
+ assertEquals(0, dialog.findViewById<ViewGroup>(android.R.id.content).childCount)
+ assertEquals(1, hostDialogContent.childCount)
+
+ val hostDialogRoot = hostDialogContent.getChildAt(0) as ViewGroup
+ assertEquals(1, hostDialogRoot.childCount)
+ assertEquals(dialog.contentView, hostDialogRoot.getChildAt(0))
+
+ // If we are dozing, the host dialog window also fades out.
+ runOnMainThreadAndWaitForIdleSync { dialogLaunchAnimator.onDozeAmountChanged(0.5f) }
+ assertTrue(hostDialog.window!!.decorView.alpha < 1f)
+
+ // Hiding/showing/dismissing the dialog should hide/show/dismiss the host dialog given that
+ // it's a ListenableDialog.
+ runOnMainThreadAndWaitForIdleSync { dialog.hide() }
+ assertFalse(hostDialog.isShowing)
+ assertFalse(dialog.isShowing)
+
+ runOnMainThreadAndWaitForIdleSync { dialog.show() }
+ assertTrue(hostDialog.isShowing)
+ assertFalse(dialog.isShowing)
+
+ assertFalse(dialog.onStopCalled)
+ runOnMainThreadAndWaitForIdleSync { dialog.dismiss() }
+ assertFalse(hostDialog.isShowing)
+ assertFalse(dialog.isShowing)
+ assertTrue(hostDialog.wasDismissed)
+ assertTrue(dialog.onStopCalled)
+ }
+
+ private fun <T : Any> runOnMainThreadAndWaitForIdleSync(f: () -> T): T {
+ lateinit var result: T
+ context.mainExecutor.execute {
+ result = f()
+ }
+ waitForIdleSync()
+ return result
+ }
+
+ private class TestHostDialogProvider : HostDialogProvider {
+ override fun createHostDialog(
+ context: Context,
+ theme: Int,
+ onCreateCallback: () -> Unit,
+ dismissOverride: (() -> Unit) -> Unit
+ ): Dialog = TestHostDialog(context, onCreateCallback, dismissOverride)
+ }
+
+ private class TestHostDialog(
+ context: Context,
+ private val onCreateCallback: () -> Unit,
+ private val dismissOverride: (() -> Unit) -> Unit
+ ) : Dialog(context) {
+ var wasDismissed = false
+
+ init {
+ // We need to set the window type for dialogs shown by SysUI, otherwise WM will throw.
+ window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ onCreateCallback()
+ }
+
+ override fun dismiss() {
+ dismissOverride {
+ super.dismiss()
+ wasDismissed = true
+ }
+ }
+ }
+
+ private class TestDialog(context: Context) : Dialog(context), ListenableDialog {
+ private val listeners = hashSetOf<DialogListener>()
+ val contentView = View(context)
+ var onStartCalled = false
+ var onStopCalled = false
+
+ init {
+ // We need to set the window type for dialogs shown by SysUI, otherwise WM will throw.
+ window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(contentView)
+ }
+
+ override fun onStart() {
+ super.onStart()
+ onStartCalled = true
+ }
+
+ override fun onStop() {
+ super.onStart()
+ onStopCalled = true
+ }
+
+ override fun addListener(listener: DialogListener) {
+ listeners.add(listener)
+ }
+
+ override fun removeListener(listener: DialogListener) {
+ listeners.remove(listener)
+ }
+
+ override fun dismiss() {
+ super.dismiss()
+ notifyListeners { onDismiss() }
+ }
+
+ override fun hide() {
+ super.hide()
+ notifyListeners { onHide() }
+ }
+
+ override fun show() {
+ super.show()
+ notifyListeners { onShow() }
+ }
+
+ private fun notifyListeners(notify: DialogListener.() -> Unit) {
+ for (listener in HashSet(listeners)) {
+ listener.notify()
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
index 8cba25dc1b92..58e0cb259bb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
@@ -32,7 +32,7 @@ class GhostedViewLaunchAnimatorControllerTest : SysuiTestCase() {
fun animatingOrphanViewDoesNotCrash() {
val ghostedView = LinearLayout(mContext)
val controller = GhostedViewLaunchAnimatorController(ghostedView)
- val state = ActivityLaunchAnimator.State(top = 0, bottom = 0, left = 0, right = 0)
+ val state = LaunchAnimator.State(top = 0, bottom = 0, left = 0, right = 0)
controller.onIntentStarted(willAnimate = true)
controller.onLaunchAnimationStart(isExpandingFullyAbove = true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 2c686618a361..25ca8c95500b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -54,6 +54,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
// Mock
private MediaOutputController mMediaOutputController = mock(MediaOutputController.class);
+ private MediaOutputDialog mMediaOutputDialog = mock(MediaOutputDialog.class);
private MediaDevice mMediaDevice1 = mock(MediaDevice.class);
private MediaDevice mMediaDevice2 = mock(MediaDevice.class);
private Icon mIcon = mock(Icon.class);
@@ -65,7 +66,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
@Before
public void setUp() {
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController, mMediaOutputDialog);
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
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 9bd07b88417d..053851ec385d 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
@@ -39,6 +39,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+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;
@@ -63,6 +64,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
private NotificationEntryManager mNotificationEntryManager =
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
+ private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl;
private MediaOutputController mMediaOutputController;
@@ -75,7 +77,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext,
mMediaOutputController);
mMediaOutputBaseDialogImpl.onCreate(new Bundle());
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 d1a617bcc0cb..f7e60caa2624 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
@@ -49,6 +49,7 @@ import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -91,6 +92,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
private NotificationEntryManager mNotificationEntryManager =
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
+ private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
private Context mSpyContext;
private MediaOutputController mMediaOutputController;
@@ -113,7 +115,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
MediaDescription.Builder builder = new MediaDescription.Builder();
@@ -157,7 +159,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
public void start_withoutPackageName_verifyMediaControllerInit() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputController.start(mCb);
@@ -178,7 +180,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
public void stop_withoutPackageName_verifyMediaControllerDeinit() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputController.start(mCb);
@@ -449,7 +451,7 @@ public class MediaOutputControllerTest extends SysuiTestCase {
public void getNotificationLargeIcon_withoutPackageName_returnsNull() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
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 86f6bdec43f0..8a3ea562269d 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
@@ -36,6 +36,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.SysuiTestCase;
+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;
@@ -65,6 +66,7 @@ public class MediaOutputDialogTest extends SysuiTestCase {
private final NotificationEntryManager mNotificationEntryManager =
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
+ private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
private MediaOutputDialog mMediaOutputDialog;
private MediaOutputController mMediaOutputController;
@@ -74,10 +76,11 @@ public class MediaOutputDialogTest extends SysuiTestCase {
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
mMediaOutputDialog = new MediaOutputDialog(mContext, false,
mMediaOutputController, mUiEventLogger);
+ mMediaOutputDialog.show();
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice);
when(mMediaDevice.getFeatures()).thenReturn(mFeatures);
@@ -123,6 +126,7 @@ public class MediaOutputDialogTest extends SysuiTestCase {
public void onCreate_ShouldLogVisibility() {
MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false,
mMediaOutputController, mUiEventLogger);
+ 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 c296ff5cf19a..e8cd6c88956d 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
@@ -34,6 +34,7 @@ import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+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;
@@ -64,6 +65,7 @@ public class MediaOutputGroupDialogTest extends SysuiTestCase {
private NotificationEntryManager mNotificationEntryManager =
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
+ private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
private MediaOutputGroupDialog mMediaOutputGroupDialog;
private MediaOutputController mMediaOutputController;
@@ -73,10 +75,11 @@ public class MediaOutputGroupDialogTest extends SysuiTestCase {
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
mMediaOutputGroupDialog = new MediaOutputGroupDialog(mContext, false,
mMediaOutputController);
+ mMediaOutputGroupDialog.show();
when(mLocalMediaManager.getSelectedMediaDevice()).thenReturn(mMediaDevices);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 09a3d35d2d32..f5cab1df9fa2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -23,6 +23,7 @@ import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_RESTING;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRANSIENT;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST;
@@ -725,6 +726,20 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
verify(mIndicationAreaBottom).announceForAccessibility(eq(faceHelpMsg));
}
+ @Test
+ public void testEmptyOwnerInfoHidesIndicationArea() {
+ createController();
+
+ // GIVEN the owner info is set to an empty string
+ when(mLockPatternUtils.getDeviceOwnerInfo()).thenReturn("");
+
+ // WHEN asked to update the indication area
+ mController.setVisible(true);
+
+ // THEN the owner info should be hidden
+ verifyHideIndication(INDICATION_TYPE_OWNER_INFO);
+ }
+
private void sendUpdateDisclosureBroadcast() {
mBroadcastReceiver.onReceive(mContext, new Intent());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index c8fec0212137..fd932803ff37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -445,6 +445,20 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
verify(smartspaceView2).registerDataProvider(plugin)
}
+ @Test
+ fun testConnectAttemptBeforeInitializationShouldNotCreateSession() {
+ // GIVEN an uninitalized smartspaceView
+ // WHEN the device is provisioned
+ `when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true)
+ `when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(true)
+ deviceProvisionedListener.onDeviceProvisionedChanged()
+
+ // THEN no calls to createSmartspaceSession should occur
+ verify(smartspaceManager, never()).createSmartspaceSession(any())
+ // THEN no listeners should be registered
+ verify(configurationController, never()).addCallback(any())
+ }
+
private fun connectSession() {
val view = controller.buildAndConnectView(fakeParent)
smartspaceView = view as SmartspaceView
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 5115614f8bfb..6e3d5ce7953e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -308,18 +308,4 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
verify(mBouncer).updateKeyguardPosition(1.0f);
}
-
- @Test
- public void testNavBarHiddenWhenSleepAnimationStarts() {
- mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */);
- assertTrue(mStatusBarKeyguardViewManager.isNavBarVisible());
-
- // Verify that the nav bar is hidden when the screen off animation starts
- doReturn(true).when(mUnlockedScreenOffAnimationController).isScreenOffAnimationPlaying();
- mWakefulnessLifecycle.dispatchFinishedGoingToSleep();
- assertFalse(mStatusBarKeyguardViewManager.isNavBarVisible());
-
- mWakefulnessLifecycle.dispatchFinishedWakingUp();
- assertTrue(mStatusBarKeyguardViewManager.isNavBarVisible());
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 88a3827d0582..fada64e02ac8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -77,6 +77,8 @@ import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollectorFake;
@@ -274,6 +276,8 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private StartingSurface mStartingSurface;
@Mock private OperatorNameViewController mOperatorNameViewController;
@Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
+ @Mock private ActivityLaunchAnimator mActivityLaunchAnimator;
+ @Mock private DialogLaunchAnimator mDialogLaunchAnimator;
private ShadeController mShadeController;
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@@ -452,7 +456,9 @@ public class StatusBarTest extends SysuiTestCase {
mUnlockedScreenOffAnimationController,
Optional.of(mStartingSurface),
mTunerService,
- mock(DumpManager.class));
+ mock(DumpManager.class),
+ mActivityLaunchAnimator,
+ mDialogLaunchAnimator);
when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class),
any(NotificationPanelViewController.class), any(BiometricUnlockController.class),
any(ViewGroup.class), any(KeyguardBypassController.class)))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
index 3cb19e3460dd..de86821c0535 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
@@ -91,7 +91,7 @@ class WallpaperControllerTest : SysuiTestCase() {
@Test
fun setUnfoldTransitionZoom_defaultUnfoldTransitionIsDisabled_doesNotUpdateWallpaperZoom() {
wallaperController.onWallpaperInfoUpdated(createWallpaperInfo(
- useDefaultUnfoldTransition = false
+ useDefaultTransition = false
))
wallaperController.setUnfoldTransitionZoom(0.5f)
@@ -136,9 +136,10 @@ class WallpaperControllerTest : SysuiTestCase() {
verify(wallpaperManager).setWallpaperZoomOut(any(), anyFloat())
}
- private fun createWallpaperInfo(useDefaultUnfoldTransition: Boolean = true): WallpaperInfo {
+ private fun createWallpaperInfo(useDefaultTransition: Boolean = true): WallpaperInfo {
val info = mock(WallpaperInfo::class.java)
- whenever(info.shouldUseDefaultUnfoldTransition()).thenReturn(useDefaultUnfoldTransition)
+ whenever(info.shouldUseDefaultDeviceStateChangeTransition())
+ .thenReturn(useDefaultTransition)
return info
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2b1c69546248..18ed9586d263 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1550,6 +1550,13 @@ public class ActivityManagerService extends IActivityManager.Stub
private static final int INDEX_TOTAL_MEMTRACK_GL = 14;
private static final int INDEX_LAST = 15;
+ /**
+ * Used to notify activity lifecycle events.
+ */
+ @Nullable
+ volatile ActivityManagerInternal.VoiceInteractionManagerProvider
+ mVoiceInteractionManagerProvider;
+
final class UiHandler extends Handler {
public UiHandler() {
super(com.android.server.UiThread.get().getLooper(), null, true);
@@ -1886,6 +1893,14 @@ public class ActivityManagerService extends IActivityManager.Stub
return mAppOpsService;
}
+ /**
+ * Sets the internal voice interaction manager service.
+ */
+ private void setVoiceInteractionManagerProvider(
+ @Nullable ActivityManagerInternal.VoiceInteractionManagerProvider provider) {
+ mVoiceInteractionManagerProvider = provider;
+ }
+
static class MemBinder extends Binder {
ActivityManagerService mActivityManagerService;
private final PriorityDump.PriorityDumper mPriorityDumper =
@@ -2737,6 +2752,11 @@ public class ActivityManagerService extends IActivityManager.Stub
|| event == Event.ACTIVITY_DESTROYED)) {
contentCaptureService.notifyActivityEvent(userId, activity, event);
}
+ // TODO(b/201234353): Move the logic to client side.
+ if (mVoiceInteractionManagerProvider != null && (event == Event.ACTIVITY_PAUSED
+ || event == Event.ACTIVITY_RESUMED || event == Event.ACTIVITY_STOPPED)) {
+ mVoiceInteractionManagerProvider.notifyActivityEventChanged();
+ }
}
/**
@@ -16366,6 +16386,12 @@ public class ActivityManagerService extends IActivityManager.Stub
return ActivityManagerService.this.sendIntentSender(target, allowlistToken, code,
intent, resolvedType, finishedReceiver, requiredPermission, options);
}
+
+ @Override
+ public void setVoiceInteractionManagerProvider(
+ @Nullable ActivityManagerInternal.VoiceInteractionManagerProvider provider) {
+ ActivityManagerService.this.setVoiceInteractionManagerProvider(provider);
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8c192844c891..e09ba346f8d8 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2635,18 +2635,19 @@ public class AudioService extends IAudioService.Stub
case KeyEvent.KEYCODE_VOLUME_UP:
adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE,
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
- Binder.getCallingUid(), true, keyEventMode);
+ Binder.getCallingUid(), Binder.getCallingPid(), true, keyEventMode);
break;
case KeyEvent.KEYCODE_VOLUME_DOWN:
adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
- Binder.getCallingUid(), true, keyEventMode);
+ Binder.getCallingUid(), Binder.getCallingPid(), true, keyEventMode);
break;
case KeyEvent.KEYCODE_VOLUME_MUTE:
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
adjustSuggestedStreamVolume(AudioManager.ADJUST_TOGGLE_MUTE,
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
- Binder.getCallingUid(), true, VOL_ADJUST_NORMAL);
+ Binder.getCallingUid(), Binder.getCallingPid(),
+ true, VOL_ADJUST_NORMAL);
}
break;
default:
@@ -2659,8 +2660,8 @@ public class AudioService extends IAudioService.Stub
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
String callingPackage, String caller) {
adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
- caller, Binder.getCallingUid(), callingHasAudioSettingsPermission(),
- VOL_ADJUST_NORMAL);
+ caller, Binder.getCallingUid(), Binder.getCallingPid(),
+ callingHasAudioSettingsPermission(), VOL_ADJUST_NORMAL);
}
public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) {
@@ -2686,7 +2687,7 @@ public class AudioService extends IAudioService.Stub
}
private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
- String callingPackage, String caller, int uid, boolean hasModifyAudioSettings,
+ String callingPackage, String caller, int uid, int pid, boolean hasModifyAudioSettings,
int keyEventMode) {
if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
+ ", flags=" + flags + ", caller=" + caller
@@ -2759,7 +2760,7 @@ public class AudioService extends IAudioService.Stub
if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
}
- adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid,
+ adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid, pid,
hasModifyAudioSettings, keyEventMode);
}
@@ -2791,12 +2792,12 @@ public class AudioService extends IAudioService.Stub
sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_STREAM_VOL, streamType,
direction/*val1*/, flags/*val2*/, callingPackage));
adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
- Binder.getCallingUid(), callingHasAudioSettingsPermission(),
- VOL_ADJUST_NORMAL);
+ Binder.getCallingUid(), Binder.getCallingPid(),
+ callingHasAudioSettingsPermission(), VOL_ADJUST_NORMAL);
}
protected void adjustStreamVolume(int streamType, int direction, int flags,
- String callingPackage, String caller, int uid, boolean hasModifyAudioSettings,
+ String callingPackage, String caller, int uid, int pid, boolean hasModifyAudioSettings,
int keyEventMode) {
if (mUseFixedVolume) {
return;
@@ -2818,8 +2819,7 @@ public class AudioService extends IAudioService.Stub
if (isMuteAdjust &&
(streamType == AudioSystem.STREAM_VOICE_CALL ||
streamType == AudioSystem.STREAM_BLUETOOTH_SCO) &&
- mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.MODIFY_PHONE_STATE)
+ mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
!= PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: adjustStreamVolume from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
@@ -2829,8 +2829,8 @@ public class AudioService extends IAudioService.Stub
// If the stream is STREAM_ASSISTANT,
// make sure that the calling app have the MODIFY_AUDIO_ROUTING permission.
if (streamType == AudioSystem.STREAM_ASSISTANT &&
- mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ mContext.checkPermission(
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING, pid, uid)
!= PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "MODIFY_AUDIO_ROUTING Permission Denial: adjustStreamVolume from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
@@ -4014,7 +4014,7 @@ public class AudioService extends IAudioService.Stub
}
private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid,
- int userId) {
+ int userId, int pid) {
// If we are being called by the system check for user we are going to change
// so we handle user restrictions correctly.
if (uid == android.os.Process.SYSTEM_UID) {
@@ -4025,8 +4025,8 @@ public class AudioService extends IAudioService.Stub
return;
}
if (userId != UserHandle.getCallingUserId() &&
- mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ mContext.checkPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ pid, uid)
!= PackageManager.PERMISSION_GRANTED) {
return;
}
@@ -4066,7 +4066,7 @@ public class AudioService extends IAudioService.Stub
public void setMasterMute(boolean mute, int flags, String callingPackage, int userId) {
enforceModifyAudioRoutingPermission();
setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid(),
- userId);
+ userId, Binder.getCallingPid());
}
/** @see AudioManager#getStreamVolume(int) */
@@ -4967,8 +4967,8 @@ public class AudioService extends IAudioService.Stub
// direction and stream type swap here because the public
// adjustSuggested has a different order than the other methods.
- adjustSuggestedStreamVolume(direction, streamType, flags, packageName, packageName, uid,
- hasAudioSettingsPermission(uid, pid), VOL_ADJUST_NORMAL);
+ adjustSuggestedStreamVolume(direction, streamType, flags, packageName, packageName,
+ uid, pid, hasAudioSettingsPermission(uid, pid), VOL_ADJUST_NORMAL);
}
/** @see AudioManager#adjustStreamVolumeForUid(int, int, int, String, int, int, int) */
@@ -4987,7 +4987,7 @@ public class AudioService extends IAudioService.Stub
.toString()));
}
- adjustStreamVolume(streamType, direction, flags, packageName, packageName, uid,
+ adjustStreamVolume(streamType, direction, flags, packageName, packageName, uid, pid,
hasAudioSettingsPermission(uid, pid), VOL_ADJUST_NORMAL);
}
diff --git a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java
index a81213df6fe3..11dc1dbd25cc 100644
--- a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java
+++ b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java
@@ -175,29 +175,25 @@ final class AppCompatOverridesParser {
/**
* Parses the given {@code configStr}, that is expected to be a comma separated list of changes
- * overrides, and returns a {@link PackageOverrides}.
+ * overrides, and returns a map from change ID to {@link PackageOverride} instances to add.
*
* <p>Each change override is in the following format:
- * '<change-id>:<min-version-code?>:<max-version-code?>:<enabled?>'. If <enabled> is empty,
- * this indicates that any override for the specified change ID should be removed.
+ * '<change-id>:<min-version-code?>:<max-version-code?>:<enabled>'.
*
* <p>If there are multiple overrides that should be added with the same change ID, the one
* that best fits the given {@code versionCode} is added.
*
* <p>Any overrides whose change ID is in {@code changeIdsToSkip} are ignored.
*
- * <p>If a change override entry in {@code configStr} is invalid, it will be ignored. If the
- * same change ID is both added and removed, i.e., has a change override entry with an empty
- * enabled and another with a non-empty enabled, the change ID will only be removed.
+ * <p>If a change override entry in {@code configStr} is invalid, it will be ignored.
*/
- static PackageOverrides parsePackageOverrides(
- String configStr, long versionCode, Set<Long> changeIdsToSkip) {
+ static Map<Long, PackageOverride> parsePackageOverrides(String configStr, long versionCode,
+ Set<Long> changeIdsToSkip) {
if (configStr.isEmpty()) {
- return new PackageOverrides();
+ return emptyMap();
}
PackageOverrideComparator comparator = new PackageOverrideComparator(versionCode);
Map<Long, PackageOverride> overridesToAdd = new ArrayMap<>();
- Set<Long> overridesToRemove = new ArraySet<>();
for (String overrideEntryString : configStr.split(",")) {
List<String> changeIdAndVersions = Arrays.asList(overrideEntryString.split(":", 4));
if (changeIdAndVersions.size() != 4) {
@@ -220,16 +216,6 @@ final class AppCompatOverridesParser {
String maxVersionCodeStr = changeIdAndVersions.get(2);
String enabledStr = changeIdAndVersions.get(3);
- if (enabledStr.isEmpty()) {
- if (!minVersionCodeStr.isEmpty() || !maxVersionCodeStr.isEmpty()) {
- Slog.w(
- TAG,
- "min/max version code should be empty if enabled is empty: "
- + overrideEntryString);
- }
- overridesToRemove.add(changeId);
- continue;
- }
if (!BOOLEAN_PATTERN.matcher(enabledStr).matches()) {
Slog.w(TAG, "Invalid enabled string in override entry: " + overrideEntryString);
continue;
@@ -262,39 +248,7 @@ final class AppCompatOverridesParser {
}
}
- for (Long changeId : overridesToRemove) {
- if (overridesToAdd.containsKey(changeId)) {
- Slog.w(
- TAG,
- "Change ID ["
- + changeId
- + "] is both added and removed in package override flag: "
- + configStr);
- overridesToAdd.remove(changeId);
- }
- }
-
- return new PackageOverrides(overridesToAdd, overridesToRemove);
- }
-
- /**
- * A container for a map from change ID to {@link PackageOverride} to add and a set of change
- * IDs to remove overrides for.
- *
- * <p>The map of overrides to add and the set of overrides to remove are mutually exclusive.
- */
- static final class PackageOverrides {
- public final Map<Long, PackageOverride> overridesToAdd;
- public final Set<Long> overridesToRemove;
-
- PackageOverrides() {
- this(emptyMap(), emptySet());
- }
-
- PackageOverrides(Map<Long, PackageOverride> overridesToAdd, Set<Long> overridesToRemove) {
- this.overridesToAdd = overridesToAdd;
- this.overridesToRemove = overridesToRemove;
- }
+ return overridesToAdd;
}
/**
diff --git a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
index 63ae1af42f08..6aed4b023297 100644
--- a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
+++ b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
@@ -49,7 +49,6 @@ import com.android.internal.compat.CompatibilityOverrideConfig;
import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
import com.android.internal.compat.IPlatformCompat;
import com.android.server.SystemService;
-import com.android.server.compat.overrides.AppCompatOverridesParser.PackageOverrides;
import java.util.ArrayList;
import java.util.Arrays;
@@ -128,20 +127,25 @@ public final class AppCompatOverridesService {
}
/**
- * Same as {@link #applyOverrides(Properties, Map)} except all properties of the given {@code
- * namespace} are fetched via {@link DeviceConfig#getProperties}.
+ * Same as {@link #applyOverrides(Properties, Set, Map)} except all properties of the given
+ * {@code namespace} are fetched via {@link DeviceConfig#getProperties}.
*/
- private void applyAllOverrides(String namespace,
+ private void applyAllOverrides(String namespace, Set<Long> ownedChangeIds,
Map<String, Set<Long>> packageToChangeIdsToSkip) {
- applyOverrides(DeviceConfig.getProperties(namespace), packageToChangeIdsToSkip);
+ applyOverrides(DeviceConfig.getProperties(namespace), ownedChangeIds,
+ packageToChangeIdsToSkip);
}
/**
* Iterates all package override flags in the given {@code properties}, and for each flag whose
- * package is installed on the device, parses its value and applies the overrides in it with
+ * package is installed on the device, parses its value and adds the overrides in it with
* respect to the package's current installed version.
+ *
+ * <p>In addition, for each package, removes any override that wasn't just added, whose change
+ * ID is in {@code ownedChangeIds} but not in the respective set in {@code
+ * packageToChangeIdsToSkip}.
*/
- private void applyOverrides(Properties properties,
+ private void applyOverrides(Properties properties, Set<Long> ownedChangeIds,
Map<String, Set<Long>> packageToChangeIdsToSkip) {
Set<String> packageNames = new ArraySet<>(properties.getKeyset());
packageNames.remove(FLAG_OWNED_CHANGE_IDS);
@@ -154,15 +158,16 @@ public final class AppCompatOverridesService {
}
applyPackageOverrides(properties.getString(packageName, /* defaultValue= */ ""),
- packageName, versionCode,
- packageToChangeIdsToSkip.getOrDefault(packageName, emptySet()));
+ packageName, versionCode, ownedChangeIds,
+ packageToChangeIdsToSkip.getOrDefault(packageName, emptySet()),
+ /* removeOtherOwnedOverrides= */ true);
}
}
/**
- * Applies all overrides in all supported namespaces for the given {@code packageName}.
+ * Adds all overrides in all supported namespaces for the given {@code packageName}.
*/
- private void applyAllPackageOverrides(String packageName) {
+ private void addAllPackageOverrides(String packageName) {
Long versionCode = getVersionCodeOrNull(packageName);
if (versionCode == null) {
return;
@@ -171,26 +176,40 @@ public final class AppCompatOverridesService {
for (String namespace : mSupportedNamespaces) {
// We apply overrides for each namespace separately so that if there is a failure for
// one namespace, the other namespaces won't be affected.
+ Set<Long> ownedChangeIds = getOwnedChangeIds(namespace);
applyPackageOverrides(
DeviceConfig.getString(namespace, packageName, /* defaultValue= */ ""),
- packageName, versionCode,
- getOverridesToRemove(namespace).getOrDefault(packageName, emptySet()));
+ packageName, versionCode, ownedChangeIds,
+ getOverridesToRemove(namespace, ownedChangeIds).getOrDefault(packageName,
+ emptySet()), /* removeOtherOwnedOverrides */ false);
}
}
/**
- * Calls {@link AppCompatOverridesParser#parsePackageOverrides} on the given arguments, adds the
- * resulting {@link PackageOverrides#overridesToAdd} via {@link
- * IPlatformCompat#putOverridesOnReleaseBuilds}, and removes the resulting {@link
- * PackageOverrides#overridesToRemove} via {@link
- * IPlatformCompat#removeOverridesOnReleaseBuilds}.
+ * Calls {@link AppCompatOverridesParser#parsePackageOverrides} on the given arguments and adds
+ * the resulting overrides via {@link IPlatformCompat#putOverridesOnReleaseBuilds}.
+ *
+ * <p>In addition, if {@code removeOtherOwnedOverrides} is true, removes any override that
+ * wasn't just added, whose change ID is in {@code ownedChangeIds} but not in {@code
+ * changeIdsToSkip}, via {@link IPlatformCompat#removeOverridesOnReleaseBuilds}.
*/
- private void applyPackageOverrides(String configStr, String packageName,
- long versionCode, Set<Long> changeIdsToSkip) {
- PackageOverrides packageOverrides = AppCompatOverridesParser.parsePackageOverrides(
+ private void applyPackageOverrides(String configStr, String packageName, long versionCode,
+ Set<Long> ownedChangeIds, Set<Long> changeIdsToSkip,
+ boolean removeOtherOwnedOverrides) {
+ Map<Long, PackageOverride> overridesToAdd = AppCompatOverridesParser.parsePackageOverrides(
configStr, versionCode, changeIdsToSkip);
- putPackageOverrides(packageName, packageOverrides.overridesToAdd);
- removePackageOverrides(packageName, packageOverrides.overridesToRemove);
+ putPackageOverrides(packageName, overridesToAdd);
+
+ if (!removeOtherOwnedOverrides) {
+ return;
+ }
+ Set<Long> overridesToRemove = new ArraySet<>();
+ for (Long changeId : ownedChangeIds) {
+ if (!overridesToAdd.containsKey(changeId) && !changeIdsToSkip.contains(changeId)) {
+ overridesToRemove.add(changeId);
+ }
+ }
+ removePackageOverrides(packageName, overridesToRemove);
}
/**
@@ -227,10 +246,11 @@ public final class AppCompatOverridesService {
* {@code namespace} and parses it into a map from package name to a set of change IDs to
* remove for that package.
*/
- private Map<String, Set<Long>> getOverridesToRemove(String namespace) {
+ private Map<String, Set<Long>> getOverridesToRemove(String namespace,
+ Set<Long> ownedChangeIds) {
return mOverridesParser.parseRemoveOverrides(
DeviceConfig.getString(namespace, FLAG_REMOVE_OVERRIDES, /* defaultValue= */ ""),
- getOwnedChangeIds(namespace));
+ ownedChangeIds);
}
/**
@@ -333,7 +353,9 @@ public final class AppCompatOverridesService {
boolean ownedChangedIdsFlagChanged = properties.getKeyset().contains(
FLAG_OWNED_CHANGE_IDS);
- Map<String, Set<Long>> overridesToRemove = getOverridesToRemove(mNamespace);
+ Set<Long> ownedChangeIds = getOwnedChangeIds(mNamespace);
+ Map<String, Set<Long>> overridesToRemove = getOverridesToRemove(mNamespace,
+ ownedChangeIds);
if (removeOverridesFlagChanged || ownedChangedIdsFlagChanged) {
// In both cases it's possible that overrides that weren't removed before should
// now be removed.
@@ -343,9 +365,9 @@ public final class AppCompatOverridesService {
if (removeOverridesFlagChanged) {
// We need to re-apply all overrides in the namespace since the remove overrides
// flag might have blocked some of them from being applied before.
- applyAllOverrides(mNamespace, overridesToRemove);
+ applyAllOverrides(mNamespace, ownedChangeIds, overridesToRemove);
} else {
- applyOverrides(properties, overridesToRemove);
+ applyOverrides(properties, ownedChangeIds, overridesToRemove);
}
}
}
@@ -392,7 +414,7 @@ public final class AppCompatOverridesService {
switch (action) {
case ACTION_PACKAGE_ADDED:
case ACTION_PACKAGE_CHANGED:
- applyAllPackageOverrides(packageName);
+ addAllPackageOverrides(packageName);
break;
case ACTION_PACKAGE_REMOVED:
if (!isInstalledForAnyUser(packageName)) {
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 5797b061f2d0..5fc301e60b9d 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -53,6 +53,7 @@ import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.view.Display;
import android.view.DisplayInfo;
@@ -77,7 +78,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Objects;
-
/**
* The DisplayModeDirector is responsible for determining what modes are allowed to be automatically
* picked by the system based on system-wide and display-specific configuration.
@@ -92,6 +92,8 @@ public class DisplayModeDirector {
private static final int MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED = 4;
private static final int MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED = 5;
private static final int MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED = 6;
+ private static final int MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED = 7;
+ private static final int MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED = 8;
// Special ID used to indicate that given vote is to be applied globally, rather than to a
// specific display.
@@ -161,9 +163,10 @@ public class DisplayModeDirector {
}
};
mSensorObserver = new SensorObserver(context, ballotBox, injector);
- mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, ballotBox);
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
+ mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler(),
+ mDeviceConfigDisplaySettings);
mDeviceConfig = injector.getDeviceConfig();
mAlwaysRespectAppRequest = false;
}
@@ -724,6 +727,11 @@ public class DisplayModeDirector {
}
@VisibleForTesting
+ HbmObserver getHbmObserver() {
+ return mHbmObserver;
+ }
+
+ @VisibleForTesting
DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
synchronized (mLock) {
@@ -792,6 +800,19 @@ public class DisplayModeDirector {
(DesiredDisplayModeSpecsListener) msg.obj;
desiredDisplayModeSpecsListener.onDesiredDisplayModeSpecsChanged();
break;
+
+ case MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED: {
+ int refreshRateInHbmSunlight = msg.arg1;
+ mHbmObserver.onDeviceConfigRefreshRateInHbmSunlightChanged(
+ refreshRateInHbmSunlight);
+ break;
+ }
+
+ case MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED: {
+ int refreshRateInHbmHdr = msg.arg1;
+ mHbmObserver.onDeviceConfigRefreshRateInHbmHdrChanged(refreshRateInHbmHdr);
+ break;
+ }
}
}
}
@@ -918,16 +939,19 @@ public class DisplayModeDirector {
// result is a range.
public static final int PRIORITY_FLICKER_REFRESH_RATE = 1;
+ // High-brightness-mode may need a specific range of refresh-rates to function properly.
+ public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 2;
+
// SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate.
// It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY]
- public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 2;
+ public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 3;
// APP_REQUEST_REFRESH_RATE_RANGE is used to for internal apps to limit the refresh
// rate in certain cases, mostly to preserve power.
// @see android.view.WindowManager.LayoutParams#preferredMinRefreshRate
// @see android.view.WindowManager.LayoutParams#preferredMaxRefreshRate
// It votes to [preferredMinRefreshRate, preferredMaxRefreshRate].
- public static final int PRIORITY_APP_REQUEST_REFRESH_RATE_RANGE = 3;
+ public static final int PRIORITY_APP_REQUEST_REFRESH_RATE_RANGE = 4;
// We split the app request into different priorities in case we can satisfy one desire
// without the other.
@@ -942,27 +966,24 @@ public class DisplayModeDirector {
// The preferred refresh rate is set on the main surface of the app outside of
// DisplayModeDirector.
// @see com.android.server.wm.WindowState#updateFrameRateSelectionPriorityIfNeeded
- public static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 4;
- public static final int PRIORITY_APP_REQUEST_SIZE = 5;
+ public static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 5;
+ public static final int PRIORITY_APP_REQUEST_SIZE = 6;
// SETTING_PEAK_REFRESH_RATE has a high priority and will restrict the bounds of the rest
// of low priority voters. It votes [0, max(PEAK, MIN)]
- public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 6;
+ public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 7;
// LOW_POWER_MODE force display to [0, 60HZ] if Settings.Global.LOW_POWER_MODE is on.
- public static final int PRIORITY_LOW_POWER_MODE = 7;
+ public static final int PRIORITY_LOW_POWER_MODE = 8;
// PRIORITY_FLICKER_REFRESH_RATE_SWITCH votes for disabling refresh rate switching. If the
// higher priority voters' result is a range, it will fix the rate to a single choice.
// It's used to avoid refresh rate switches in certain conditions which may result in the
// user seeing the display flickering when the switches occur.
- public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8;
+ public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 9;
// Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
- public static final int PRIORITY_SKIN_TEMPERATURE = 9;
-
- // High-brightness-mode may need a specific range of refresh-rates to function properly.
- public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 10;
+ public static final int PRIORITY_SKIN_TEMPERATURE = 10;
// The proximity sensor needs the refresh rate to be locked in order to function, so this is
// set to a high priority.
@@ -2258,33 +2279,78 @@ public class DisplayModeDirector {
* HBM that are associated with that display. Restrictions are retrieved from
* DisplayManagerInternal but originate in the display-device-config file.
*/
- private static class HbmObserver implements DisplayManager.DisplayListener {
+ public static class HbmObserver implements DisplayManager.DisplayListener {
private final BallotBox mBallotBox;
private final Handler mHandler;
- private final SparseBooleanArray mHbmEnabled = new SparseBooleanArray();
+ private final SparseIntArray mHbmMode = new SparseIntArray();
private final Injector mInjector;
+ private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
+ private int mRefreshRateInHbmSunlight;
+ private int mRefreshRateInHbmHdr;
private DisplayManagerInternal mDisplayManagerInternal;
- HbmObserver(Injector injector, BallotBox ballotBox, Handler handler) {
+ HbmObserver(Injector injector, BallotBox ballotBox, Handler handler,
+ DeviceConfigDisplaySettings displaySettings) {
mInjector = injector;
mBallotBox = ballotBox;
mHandler = handler;
+ mDeviceConfigDisplaySettings = displaySettings;
}
public void observe() {
+ mRefreshRateInHbmSunlight = mDeviceConfigDisplaySettings.getRefreshRateInHbmSunlight();
+ mRefreshRateInHbmHdr = mDeviceConfigDisplaySettings.getRefreshRateInHbmHdr();
+
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mInjector.registerDisplayListener(this, mHandler,
DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
}
+ /**
+ * @return the refresh to lock to when the device is in high brightness mode for Sunlight.
+ */
+ @VisibleForTesting
+ int getRefreshRateInHbmSunlight() {
+ return mRefreshRateInHbmSunlight;
+ }
+
+ /**
+ * @return the refresh to lock to when the device is in high brightness mode for HDR.
+ */
+ @VisibleForTesting
+ int getRefreshRateInHbmHdr() {
+ return mRefreshRateInHbmHdr;
+ }
+
+ /**
+ * Recalculates the HBM vote when the device config has been changed.
+ */
+ public void onDeviceConfigRefreshRateInHbmSunlightChanged(int refreshRate) {
+ if (refreshRate != mRefreshRateInHbmSunlight) {
+ mRefreshRateInHbmSunlight = refreshRate;
+ onDeviceConfigRefreshRateInHbmChanged();
+ }
+ }
+
+ /**
+ * Recalculates the HBM vote when the device config has been changed.
+ */
+ public void onDeviceConfigRefreshRateInHbmHdrChanged(int refreshRate) {
+ if (refreshRate != mRefreshRateInHbmHdr) {
+ mRefreshRateInHbmHdr = refreshRate;
+ onDeviceConfigRefreshRateInHbmChanged();
+ }
+ }
+
@Override
public void onDisplayAdded(int displayId) {}
@Override
public void onDisplayRemoved(int displayId) {
mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null);
+ mHbmMode.delete(displayId);
}
@Override
@@ -2294,31 +2360,56 @@ public class DisplayModeDirector {
// Display no longer there. Assume we'll get an onDisplayRemoved very soon.
return;
}
- final boolean isHbmEnabled =
- info.highBrightnessMode != BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
- if (isHbmEnabled == mHbmEnabled.get(displayId)) {
+ final int hbmMode = info.highBrightnessMode;
+ if (hbmMode == mHbmMode.get(displayId)) {
// no change, ignore.
return;
}
+ mHbmMode.put(displayId, hbmMode);
+ recalculateVotesForDisplay(displayId);
+ }
+
+ private void onDeviceConfigRefreshRateInHbmChanged() {
+ final int[] displayIds = mHbmMode.copyKeys();
+ if (displayIds != null) {
+ for (int id : displayIds) {
+ recalculateVotesForDisplay(id);
+ }
+ }
+ }
+
+ private void recalculateVotesForDisplay(int displayId) {
+ final int hbmMode = mHbmMode.get(displayId, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF);
Vote vote = null;
- mHbmEnabled.put(displayId, isHbmEnabled);
- if (isHbmEnabled) {
- final List<RefreshRateLimitation> limits =
+ if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT) {
+ // Device resource properties take priority over DisplayDeviceConfig
+ if (mRefreshRateInHbmSunlight > 0) {
+ vote = Vote.forRefreshRates(mRefreshRateInHbmSunlight,
+ mRefreshRateInHbmSunlight);
+ } else {
+ final List<RefreshRateLimitation> limits =
mDisplayManagerInternal.getRefreshRateLimitations(displayId);
- for (int i = 0; limits != null && i < limits.size(); i++) {
- final RefreshRateLimitation limitation = limits.get(i);
- if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) {
- vote = Vote.forRefreshRates(limitation.range.min, limitation.range.max);
- break;
+ for (int i = 0; limits != null && i < limits.size(); i++) {
+ final RefreshRateLimitation limitation = limits.get(i);
+ if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) {
+ vote = Vote.forRefreshRates(limitation.range.min, limitation.range.max);
+ break;
+ }
}
}
}
+ if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
+ && mRefreshRateInHbmHdr > 0) {
+ vote = Vote.forRefreshRates(mRefreshRateInHbmHdr, mRefreshRateInHbmHdr);
+ }
mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote);
}
void dumpLocked(PrintWriter pw) {
pw.println(" HbmObserver");
- pw.println(" mHbmEnabled: " + mHbmEnabled);
+ pw.println(" mHbmMode: " + mHbmMode);
+ pw.println(" mRefreshRateInHbmSunlight: " + mRefreshRateInHbmSunlight);
+ pw.println(" mRefreshRateInHbmHdr: " + mRefreshRateInHbmHdr);
}
}
@@ -2437,6 +2528,29 @@ public class DisplayModeDirector {
return refreshRate;
}
+ public int getRefreshRateInHbmSunlight() {
+ final int defaultRefreshRateInHbmSunlight =
+ mContext.getResources().getInteger(
+ R.integer.config_defaultRefreshRateInHbmSunlight);
+
+ final int refreshRate = mDeviceConfig.getInt(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_SUNLIGHT,
+ defaultRefreshRateInHbmSunlight);
+
+ return refreshRate;
+ }
+
+ public int getRefreshRateInHbmHdr() {
+ final int defaultRefreshRateInHbmHdr =
+ mContext.getResources().getInteger(R.integer.config_defaultRefreshRateInHbmHdr);
+
+ final int refreshRate = mDeviceConfig.getInt(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_HDR,
+ defaultRefreshRateInHbmHdr);
+
+ return refreshRate;
+ }
+
/*
* Return null if no such property
*/
@@ -2476,6 +2590,15 @@ public class DisplayModeDirector {
.sendToTarget();
mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone, 0)
.sendToTarget();
+
+ final int refreshRateInHbmSunlight = getRefreshRateInHbmSunlight();
+ mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED,
+ refreshRateInHbmSunlight, 0)
+ .sendToTarget();
+
+ final int refreshRateInHbmHdr = getRefreshRateInHbmHdr();
+ mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED, refreshRateInHbmHdr, 0)
+ .sendToTarget();
}
private int[] getIntArrayProperty(String prop) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 45f5daac8dd9..dd2583a0ce1a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -508,7 +508,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private boolean mKeyguardOccludedChanged;
private ActivityTaskManagerInternal.SleepTokenAcquirer mScreenOffSleepTokenAcquirer;
- volatile boolean mKeyguardOccluded;
Intent mHomeIntent;
Intent mCarDockIntent;
Intent mDeskDockIntent;
@@ -2399,7 +2398,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// the keyguard is being hidden. This is okay because starting windows never show
// secret information.
// TODO(b/113840485): Occluded may not only happen on default display
- if (displayId == DEFAULT_DISPLAY && mKeyguardOccluded) {
+ if (displayId == DEFAULT_DISPLAY && isKeyguardOccluded()) {
windowFlags |= FLAG_SHOW_WHEN_LOCKED;
}
}
@@ -3215,7 +3214,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return;
}
- if (!mKeyguardOccluded && mKeyguardDelegate.isInputRestricted()) {
+ if (!isKeyguardOccluded() && mKeyguardDelegate.isInputRestricted()) {
// when in keyguard restricted mode, must first verify unlock
// before launching home
mKeyguardDelegate.verifyUnlock(new OnKeyguardExitResult() {
@@ -3266,42 +3265,38 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public void setKeyguardCandidateLw(WindowState win) {
mKeyguardCandidate = win;
- setKeyguardOccludedLw(mKeyguardOccluded, true /* force */);
+ setKeyguardOccludedLw(isKeyguardOccluded(), true /* force */);
}
/**
* Updates the occluded state of the Keyguard.
*
+ * @param isOccluded Whether the Keyguard is occluded by another window.
+ * @param force notify the occluded status to KeyguardService and update flags even though
+ * occlude status doesn't change.
* @return Whether the flags have changed and we have to redo the layout.
*/
private boolean setKeyguardOccludedLw(boolean isOccluded, boolean force) {
if (DEBUG_KEYGUARD) Slog.d(TAG, "setKeyguardOccluded occluded=" + isOccluded);
- final boolean wasOccluded = mKeyguardOccluded;
+ if (isKeyguardOccluded() == isOccluded && !force) {
+ return false;
+ }
+
final boolean showing = mKeyguardDelegate.isShowing();
- final boolean changed = wasOccluded != isOccluded || force;
- if (!isOccluded && changed && showing) {
- mKeyguardOccluded = false;
- mKeyguardDelegate.setOccluded(false, true /* animate */);
- if (mKeyguardCandidate != null) {
- if (!mKeyguardDelegate.hasLockscreenWallpaper()) {
- mKeyguardCandidate.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
- }
- }
- return true;
- } else if (isOccluded && changed && showing) {
- mKeyguardOccluded = true;
- mKeyguardDelegate.setOccluded(true, false /* animate */);
- if (mKeyguardCandidate != null) {
+ final boolean animate = showing && !isOccluded;
+ mKeyguardDelegate.setOccluded(isOccluded, animate);
+
+ if (!showing) {
+ return false;
+ }
+ if (mKeyguardCandidate != null) {
+ if (isOccluded) {
mKeyguardCandidate.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
+ } else if (!mKeyguardDelegate.hasLockscreenWallpaper()) {
+ mKeyguardCandidate.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
}
- return true;
- } else if (changed) {
- mKeyguardOccluded = isOccluded;
- mKeyguardDelegate.setOccluded(isOccluded, false /* animate */);
- return false;
- } else {
- return false;
}
+ return true;
}
/** {@inheritDoc} */
@@ -4596,7 +4591,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public boolean isKeyguardShowingAndNotOccluded() {
if (mKeyguardDelegate == null) return false;
- return mKeyguardDelegate.isShowing() && !mKeyguardOccluded;
+ return mKeyguardDelegate.isShowing() && !isKeyguardOccluded();
}
@Override
@@ -4622,7 +4617,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public boolean isKeyguardOccluded() {
if (mKeyguardDelegate == null) return false;
- return mKeyguardOccluded;
+ return mKeyguardDelegate.isOccluded();
}
/** {@inheritDoc} */
@@ -5308,7 +5303,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
proto.write(KEYGUARD_DRAW_COMPLETE, mDefaultDisplayPolicy.isKeyguardDrawComplete());
proto.write(WINDOW_MANAGER_DRAW_COMPLETE,
mDefaultDisplayPolicy.isWindowManagerDrawComplete());
- proto.write(KEYGUARD_OCCLUDED, mKeyguardOccluded);
+ proto.write(KEYGUARD_OCCLUDED, isKeyguardOccluded());
proto.write(KEYGUARD_OCCLUDED_CHANGED, mKeyguardOccludedChanged);
proto.write(KEYGUARD_OCCLUDED_PENDING, mPendingKeyguardOccluded);
if (mKeyguardDelegate != null) {
@@ -5393,7 +5388,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final int key = mDisplayHomeButtonHandlers.keyAt(i);
pw.println(mDisplayHomeButtonHandlers.get(key));
}
- pw.print(prefix); pw.print("mKeyguardOccluded="); pw.print(mKeyguardOccluded);
+ pw.print(prefix); pw.print("mKeyguardOccluded="); pw.print(isKeyguardOccluded());
pw.print(" mKeyguardOccludedChanged="); pw.print(mKeyguardOccludedChanged);
pw.print(" mPendingKeyguardOccluded="); pw.println(mPendingKeyguardOccluded);
pw.print(prefix); pw.print("mAllowLockscreenWhenOnDisplays=");
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 0535af57d8ab..d1906785994a 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -67,7 +67,7 @@ public class KeyguardServiceDelegate {
boolean showing;
boolean showingAndNotOccluded;
boolean inputRestricted;
- boolean occluded;
+ volatile boolean occluded;
boolean secure;
boolean dreaming;
boolean systemIsReady;
@@ -272,6 +272,10 @@ public class KeyguardServiceDelegate {
mKeyguardState.occluded = isOccluded;
}
+ public boolean isOccluded() {
+ return mKeyguardState.occluded;
+ }
+
public void dismiss(IKeyguardDismissCallback callback, CharSequence message) {
if (mKeyguardService != null) {
mKeyguardService.dismiss(callback, message);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 19a968628248..168686c04d36 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1411,7 +1411,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
this.task = newTask;
if (shouldStartChangeTransition(newParent, oldParent)) {
- initializeChangeTransition(getBounds());
+ // The new parent and old parent may be in different position. Need to offset the
+ // animation surface to keep it in its original position.
+ initializeChangeTransition(getBounds(), newParent.getBounds());
}
super.onParentChanged(newParent, oldParent);
@@ -4944,11 +4946,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// dispatchTaskInfoChangedIfNeeded() right after ActivityRecord#setVisibility() can report
// the stale visible state, because the state will be updated after the app transition.
// So tries to report the actual visible state again where the state is changed.
- if (!mTaskSupervisor.inActivityVisibilityUpdate()) {
- final Task task = getOrganizedTask();
- if (task != null) {
- task.dispatchTaskInfoChangedIfNeeded(false /* force */);
- }
+ Task task = getOrganizedTask();
+ while (task != null) {
+ task.dispatchTaskInfoChangedIfNeeded(false /* force */);
+ task = task.getParent().asTask();
}
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"commitVisibility: %s: visible=%b mVisibleRequested=%b", this,
@@ -9276,7 +9277,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
record.getMode(), record.mAdapter.mCapturedLeash, !fillsParent(),
new Rect(), insets,
getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds,
- record.mAdapter.mRootTaskBounds, task.getWindowConfiguration(),
+ record.mAdapter.mEndBounds, task.getWindowConfiguration(),
false /*isNotInRecents*/,
record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
record.mStartBounds, task.getTaskInfo(), checkEnterPictureInPictureAppOpsState());
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 0ba77d8552d3..4149980c7d45 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -596,11 +596,18 @@ public abstract class ActivityTaskManagerInternal {
public abstract boolean isBaseOfLockedTask(String packageName);
/**
- * Create an interface to update configuration for an application.
+ * Creates an interface to update configuration for the calling application.
*/
public abstract PackageConfigurationUpdater createPackageConfigurationUpdater();
/**
+ * Creates an interface to update configuration for an arbitrary application specified by it's
+ * packageName and userId.
+ */
+ public abstract PackageConfigurationUpdater createPackageConfigurationUpdater(
+ String packageName, int userId);
+
+ /**
* An interface to update configuration for an application, and will persist override
* configuration for this package.
*/
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 681ff9022e4b..f278e3e22982 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1732,10 +1732,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(bOptions);
final long origId = Binder.clearCallingIdentity();
try {
- synchronized (mGlobalLock) {
- return mTaskSupervisor.startActivityFromRecents(callingPid, callingUid, taskId,
- safeOptions);
- }
+ return mTaskSupervisor.startActivityFromRecents(callingPid, callingUid, taskId,
+ safeOptions);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -6559,6 +6557,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
+ public PackageConfigurationUpdater createPackageConfigurationUpdater(
+ String packageName , int userId) {
+ return new PackageConfigurationUpdaterImpl(packageName, userId,
+ ActivityTaskManagerService.this);
+ }
+
+ @Override
public boolean hasSystemAlertWindowPermission(int callingUid, int callingPid,
String callingPackage) {
return ActivityTaskManagerService.this.hasSystemAlertWindowPermission(callingUid,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 0497fb5001d4..145bdfda3ce3 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2474,102 +2474,126 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
}
+ /**
+ * Start the given task from the recent tasks. Do not hold WM global lock when calling this
+ * method to avoid potential deadlock or permission deny by UriGrantsManager when resolving
+ * activity (see {@link ActivityStarter.Request#resolveActivity} and
+ * {@link com.android.server.am.ContentProviderHelper#checkContentProviderUriPermission}).
+ *
+ * @return The result code of starter.
+ */
int startActivityFromRecents(int callingPid, int callingUid, int taskId,
SafeActivityOptions options) {
- Task task = null;
+ final Task task;
+ final int taskCallingUid;
final String callingPackage;
final String callingFeatureId;
final Intent intent;
final int userId;
- int activityType = ACTIVITY_TYPE_UNDEFINED;
- int windowingMode = WINDOWING_MODE_UNDEFINED;
final ActivityOptions activityOptions = options != null
? options.getOptions(this)
: null;
boolean moveHomeTaskForward = true;
- if (activityOptions != null) {
- activityType = activityOptions.getLaunchActivityType();
- windowingMode = activityOptions.getLaunchWindowingMode();
- if (activityOptions.freezeRecentTasksReordering()
- && mRecentTasks.isCallerRecents(callingUid)) {
- mRecentTasks.setFreezeTaskListReordering();
- }
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || activityOptions.getLaunchRootTask() != null) {
- // Don't move home activity forward if we are launching into primary split or there
- // is a launch root set.
- moveHomeTaskForward = false;
+ synchronized (mService.mGlobalLock) {
+ int activityType = ACTIVITY_TYPE_UNDEFINED;
+ if (activityOptions != null) {
+ activityType = activityOptions.getLaunchActivityType();
+ final int windowingMode = activityOptions.getLaunchWindowingMode();
+ if (activityOptions.freezeRecentTasksReordering()
+ && mRecentTasks.isCallerRecents(callingUid)) {
+ mRecentTasks.setFreezeTaskListReordering();
+ }
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || activityOptions.getLaunchRootTask() != null) {
+ // Don't move home activity forward if we are launching into primary split or
+ // there is a launch root set.
+ moveHomeTaskForward = false;
+ }
}
- }
- if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
- throw new IllegalArgumentException("startActivityFromRecents: Task "
- + taskId + " can't be launch in the home/recents root task.");
- }
-
- mService.deferWindowLayout();
- try {
- task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
- if (task == null) {
- mWindowManager.executeAppTransition();
- throw new IllegalArgumentException(
- "startActivityFromRecents: Task " + taskId + " not found.");
+ if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
+ throw new IllegalArgumentException("startActivityFromRecents: Task "
+ + taskId + " can't be launch in the home/recents root task.");
}
- if (moveHomeTaskForward) {
- // We always want to return to the home activity instead of the recents activity
- // from whatever is started from the recents activity, so move the home root task
- // forward.
- // TODO (b/115289124): Multi-display supports for recents.
- mRootWindowContainer.getDefaultTaskDisplayArea().moveHomeRootTaskToFront(
- "startActivityFromRecents");
- }
+ boolean shouldStartActivity = false;
+ mService.deferWindowLayout();
+ try {
+ task = mRootWindowContainer.anyTaskForId(taskId,
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
+ if (task == null) {
+ mWindowManager.executeAppTransition();
+ throw new IllegalArgumentException(
+ "startActivityFromRecents: Task " + taskId + " not found.");
+ }
- // If the user must confirm credentials (e.g. when first launching a work app and the
- // Work Challenge is present) let startActivityInPackage handle the intercepting.
- if (!mService.mAmInternal.shouldConfirmCredentials(task.mUserId)
- && task.getRootActivity() != null) {
- final ActivityRecord targetActivity = task.getTopNonFinishingActivity();
-
- mRootWindowContainer.startPowerModeLaunchIfNeeded(
- true /* forceSend */, targetActivity);
- final LaunchingState launchingState =
- mActivityMetricsLogger.notifyActivityLaunching(task.intent);
- try {
- mService.moveTaskToFrontLocked(null /* appThread */, null /* callingPackage */,
- task.mTaskId, 0, options);
- // Apply options to prevent pendingOptions be taken when scheduling activity
- // lifecycle transaction to make sure the override pending app transition will
- // be applied immediately.
- targetActivity.applyOptionsAnimation();
- } finally {
- mActivityMetricsLogger.notifyActivityLaunched(launchingState,
- START_TASK_TO_FRONT, false /* newActivityCreated */, targetActivity,
- activityOptions);
+ if (moveHomeTaskForward) {
+ // We always want to return to the home activity instead of the recents
+ // activity from whatever is started from the recents activity, so move
+ // the home root task forward.
+ // TODO (b/115289124): Multi-display supports for recents.
+ mRootWindowContainer.getDefaultTaskDisplayArea().moveHomeRootTaskToFront(
+ "startActivityFromRecents");
}
- mService.getActivityStartController().postStartActivityProcessingForLastStarter(
- task.getTopNonFinishingActivity(), ActivityManager.START_TASK_TO_FRONT,
- task.getRootTask());
+ // If the user must confirm credentials (e.g. when first launching a work
+ // app and the Work Challenge is present) let startActivityInPackage handle
+ // the intercepting.
+ if (!mService.mAmInternal.shouldConfirmCredentials(task.mUserId)
+ && task.getRootActivity() != null) {
+ final ActivityRecord targetActivity = task.getTopNonFinishingActivity();
+
+ mRootWindowContainer.startPowerModeLaunchIfNeeded(
+ true /* forceSend */, targetActivity);
+ final LaunchingState launchingState =
+ mActivityMetricsLogger.notifyActivityLaunching(task.intent);
+ try {
+ mService.moveTaskToFrontLocked(null /* appThread */,
+ null /* callingPackage */, task.mTaskId, 0, options);
+ // Apply options to prevent pendingOptions be taken when scheduling
+ // activity lifecycle transaction to make sure the override pending app
+ // transition will be applied immediately.
+ targetActivity.applyOptionsAnimation();
+ } finally {
+ mActivityMetricsLogger.notifyActivityLaunched(launchingState,
+ START_TASK_TO_FRONT, false /* newActivityCreated */,
+ targetActivity, activityOptions);
+ }
- // As it doesn't go to ActivityStarter.executeRequest() path, we need to resume
- // app switching here also.
- mService.resumeAppSwitches();
+ mService.getActivityStartController().postStartActivityProcessingForLastStarter(
+ task.getTopNonFinishingActivity(), ActivityManager.START_TASK_TO_FRONT,
+ task.getRootTask());
- return ActivityManager.START_TASK_TO_FRONT;
+ // As it doesn't go to ActivityStarter.executeRequest() path, we need to resume
+ // app switching here also.
+ mService.resumeAppSwitches();
+ return ActivityManager.START_TASK_TO_FRONT;
+ }
+ // The task is empty or needs to show the confirmation for credential.
+ shouldStartActivity = true;
+ } finally {
+ if (!shouldStartActivity) {
+ mService.continueWindowLayout();
+ }
}
+ taskCallingUid = task.mCallingUid;
callingPackage = task.mCallingPackage;
callingFeatureId = task.mCallingFeatureId;
intent = task.intent;
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
userId = task.mUserId;
- return mService.getActivityStartController().startActivityInPackage(task.mCallingUid,
+ }
+ // ActivityStarter will acquire the lock where the places need, so execute the request
+ // outside of the lock.
+ try {
+ return mService.getActivityStartController().startActivityInPackage(taskCallingUid,
callingPid, callingUid, callingPackage, callingFeatureId, intent, null, null,
null, 0, 0, options, userId, task, "startActivityFromRecents",
false /* validateIncomingUser */, null /* originatingPendingIntent */,
false /* allowBackgroundActivityStart */);
} finally {
- mService.continueWindowLayout();
+ synchronized (mService.mGlobalLock) {
+ mService.continueWindowLayout();
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java
index 486328a758da..529c4f608743 100644
--- a/services/core/java/com/android/server/wm/AnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/AnimationAdapter.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import android.annotation.ColorInt;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
@@ -107,14 +106,4 @@ interface AnimationAdapter {
default boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
return false;
}
-
- /**
- * Gets the background color to show behind an animation.
- *
- * @return The background color to show behind an animation (0 for no background color).
- */
- @ColorInt
- default int getBackgroundColor() {
- return 0;
- }
}
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 7f0adcacc951..558939611905 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -35,10 +35,10 @@ import android.os.UserHandle;
*/
class AppTaskImpl extends IAppTask.Stub {
private static final String TAG = "AppTaskImpl";
- private ActivityTaskManagerService mService;
+ private final ActivityTaskManagerService mService;
- private int mTaskId;
- private int mCallingUid;
+ private final int mTaskId;
+ private final int mCallingUid;
public AppTaskImpl(ActivityTaskManagerService service, int taskId, int callingUid) {
mService = service;
@@ -113,9 +113,9 @@ class AppTaskImpl extends IAppTask.Stub {
return;
}
}
- mService.mTaskSupervisor.startActivityFromRecents(callingPid,
- callingUid, mTaskId, null);
}
+ mService.mTaskSupervisor.startActivityFromRecents(callingPid, callingUid, mTaskId,
+ null /* options */);
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
index 8f161bf6ecc4..520bd8b2108e 100644
--- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
@@ -19,7 +19,6 @@ package com.android.server.wm;
import static com.android.server.wm.AnimationAdapterProto.LOCAL;
import static com.android.server.wm.LocalAnimationAdapterProto.ANIMATION_SPEC;
-import android.annotation.ColorInt;
import android.os.SystemClock;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
@@ -73,12 +72,6 @@ class LocalAnimationAdapter implements AnimationAdapter {
}
@Override
- @ColorInt
- public int getBackgroundColor() {
- return mSpec.getBackgroundColor();
- }
-
- @Override
public void dump(PrintWriter pw, String prefix) {
mSpec.dump(pw, prefix);
}
@@ -156,9 +149,5 @@ class LocalAnimationAdapter implements AnimationAdapter {
}
void dumpDebugInner(ProtoOutputStream proto);
-
- default int getBackgroundColor() {
- return 0;
- }
}
}
diff --git a/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java b/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java
index 960250544299..8bbcf1f9c029 100644
--- a/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java
+++ b/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java
@@ -16,24 +16,38 @@
package com.android.server.wm;
+import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.LocaleList;
+import android.util.ArraySet;
import android.util.Slog;
+import java.util.Optional;
+
/**
* An implementation of {@link ActivityTaskManagerInternal.PackageConfigurationUpdater}.
*/
final class PackageConfigurationUpdaterImpl implements
ActivityTaskManagerInternal.PackageConfigurationUpdater {
private static final String TAG = "PackageConfigurationUpdaterImpl";
- private final int mPid;
+ private final Optional<Integer> mPid;
private Integer mNightMode;
private LocaleList mLocales;
+ private String mPackageName;
+ private int mUserId;
private ActivityTaskManagerService mAtm;
PackageConfigurationUpdaterImpl(int pid, ActivityTaskManagerService atm) {
- mPid = pid;
+ mPid = Optional.of(pid);
+ mAtm = atm;
+ }
+
+ PackageConfigurationUpdaterImpl(String packageName, int userId,
+ ActivityTaskManagerService atm) {
+ mPackageName = packageName;
+ mUserId = userId;
mAtm = atm;
+ mPid = Optional.empty();
}
@Override
@@ -59,16 +73,29 @@ final class PackageConfigurationUpdaterImpl implements
synchronized (mAtm.mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
try {
- final WindowProcessController wpc = mAtm.mProcessMap.getProcess(mPid);
- if (wpc == null) {
- Slog.w(TAG, "Override application configuration: cannot find pid " + mPid);
- return;
+ final int uid;
+ if (mPid.isPresent()) {
+ WindowProcessController wpc = mAtm.mProcessMap.getProcess(mPid.get());
+ if (wpc == null) {
+ Slog.w(TAG, "commit: Override application configuration failed: "
+ + "cannot find pid " + mPid);
+ return;
+ }
+ uid = wpc.mUid;
+ mUserId = wpc.mUserId;
+ mPackageName = wpc.mInfo.packageName;
+ } else {
+ uid = mAtm.getPackageManagerInternalLocked().getPackageUid(mPackageName,
+ /* flags = */ PackageManager.MATCH_ALL, mUserId);
+ if (uid < 0) {
+ Slog.w(TAG, "commit: update of application configuration failed: "
+ + "userId or packageName not valid " + mUserId);
+ return;
+ }
}
- LocaleList localesOverride = LocaleOverlayHelper.combineLocalesIfOverlayExists(
- mLocales, mAtm.getGlobalConfiguration().getLocales());
- wpc.applyAppSpecificConfig(mNightMode, localesOverride);
- wpc.updateAppSpecificSettingsForAllActivities(mNightMode, localesOverride);
- mAtm.mPackageConfigPersister.updateFromImpl(wpc.mName, wpc.mUserId, this);
+ updateConfig(uid, mPackageName);
+ mAtm.mPackageConfigPersister.updateFromImpl(mPackageName, mUserId, this);
+
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -76,6 +103,19 @@ final class PackageConfigurationUpdaterImpl implements
}
}
+ private void updateConfig(int uid, String packageName) {
+ final ArraySet<WindowProcessController> processes = mAtm.mProcessMap.getProcesses(uid);
+ if (processes == null) return;
+ for (int i = processes.size() - 1; i >= 0; i--) {
+ final WindowProcessController wpc = processes.valueAt(i);
+ if (!wpc.mInfo.packageName.equals(packageName)) continue;
+ LocaleList localesOverride = LocaleOverlayHelper.combineLocalesIfOverlayExists(
+ mLocales, mAtm.getGlobalConfiguration().getLocales());
+ wpc.applyAppSpecificConfig(mNightMode, localesOverride);
+ wpc.updateAppSpecificSettingsForAllActivities(mNightMode, localesOverride);
+ }
+ }
+
Integer getNightMode() {
return mNightMode;
}
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index b90f937ca56e..16a45fe7cec7 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -65,7 +65,6 @@ class RemoteAnimationController implements DeathRecipient {
new ArrayList<>();
@VisibleForTesting
final ArrayList<NonAppWindowAnimationAdapter> mPendingNonAppAnimations = new ArrayList<>();
- private final Rect mTmpRect = new Rect();
private final Handler mHandler;
private final Runnable mTimeoutRunnable = () -> cancelAnimation("timeoutRunnable");
@@ -85,18 +84,18 @@ class RemoteAnimationController implements DeathRecipient {
* Creates an animation record for each individual {@link WindowContainer}.
*
* @param windowContainer The windows to animate.
- * @param position The position app bounds, in screen coordinates.
+ * @param position The position app bounds relative to its parent.
* @param localBounds The bounds of the app relative to its parent.
- * @param stackBounds The stack bounds of the app relative to position.
- * @param startBounds The stack bounds before the transition, in screen coordinates
+ * @param endBounds The end bounds after the transition, in screen coordinates.
+ * @param startBounds The start bounds before the transition, in screen coordinates.
* @return The record representing animation(s) to run on the app.
*/
RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer,
- Point position, Rect localBounds, Rect stackBounds, Rect startBounds) {
+ Point position, Rect localBounds, Rect endBounds, Rect startBounds) {
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): container=%s",
windowContainer);
final RemoteAnimationRecord adapters = new RemoteAnimationRecord(windowContainer, position,
- localBounds, stackBounds, startBounds);
+ localBounds, endBounds, startBounds);
mPendingAnimations.add(adapters);
return adapters;
}
@@ -405,16 +404,17 @@ class RemoteAnimationController implements DeathRecipient {
mStartBounds = new Rect(startBounds);
mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds,
mStartBounds);
- mTmpRect.set(startBounds);
- mTmpRect.offsetTo(0, 0);
if (mRemoteAnimationAdapter.getChangeNeedsSnapshot()) {
- mThumbnailAdapter =
- new RemoteAnimationAdapterWrapper(this, new Point(0, 0), localBounds,
- mTmpRect, new Rect());
+ final Rect thumbnailLocalBounds = new Rect(startBounds);
+ thumbnailLocalBounds.offsetTo(0, 0);
+ // Snapshot is located at (0,0) of the animation leash. It doesn't have size
+ // change, so the startBounds is its end bounds, and no start bounds for it.
+ mThumbnailAdapter = new RemoteAnimationAdapterWrapper(this, new Point(0, 0),
+ thumbnailLocalBounds, startBounds, new Rect());
}
} else {
mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds,
- new Rect(endPos.x, endPos.y, endBounds.right, endBounds.bottom));
+ new Rect());
mStartBounds = null;
}
}
@@ -458,15 +458,15 @@ class RemoteAnimationController implements DeathRecipient {
private @AnimationType int mAnimationType;
final Point mPosition = new Point();
final Rect mLocalBounds;
- final Rect mRootTaskBounds = new Rect();
+ final Rect mEndBounds = new Rect();
final Rect mStartBounds = new Rect();
RemoteAnimationAdapterWrapper(RemoteAnimationRecord record, Point position,
- Rect localBounds, Rect rootTaskBounds, Rect startBounds) {
+ Rect localBounds, Rect endBounds, Rect startBounds) {
mRecord = record;
mPosition.set(position.x, position.y);
mLocalBounds = localBounds;
- mRootTaskBounds.set(rootTaskBounds);
+ mEndBounds.set(endBounds);
mStartBounds.set(startBounds);
}
@@ -480,12 +480,17 @@ class RemoteAnimationController implements DeathRecipient {
@AnimationType int type, OnAnimationFinishedCallback finishCallback) {
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
- // Restore position and stack crop until client has a chance to modify it.
if (mStartBounds.isEmpty()) {
- t.setPosition(animationLeash, 0, 0);
- t.setWindowCrop(animationLeash, -1, -1);
+ // Restore position and stack crop until client has a chance to modify it.
+ t.setPosition(animationLeash, mPosition.x, mPosition.y);
+ t.setWindowCrop(animationLeash, mEndBounds.width(), mEndBounds.height());
} else {
- t.setPosition(animationLeash, mStartBounds.left, mStartBounds.top);
+ // Offset the change animation leash to the relative start position in parent.
+ // (mPosition) is the relative end position in parent container.
+ // (mStartBounds - mEndBounds) is the position difference between start and end.
+ // (mPosition + mStartBounds - mEndBounds) will be the relative start position.
+ t.setPosition(animationLeash, mPosition.x + mStartBounds.left - mEndBounds.left,
+ mPosition.y + mStartBounds.top - mEndBounds.top);
t.setWindowCrop(animationLeash, mStartBounds.width(), mStartBounds.height());
}
mCapturedLeash = animationLeash;
diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java
index fce2f8da10c7..9c4f6f574487 100644
--- a/services/core/java/com/android/server/wm/SurfaceFreezer.java
+++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java
@@ -24,6 +24,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.view.Surface;
@@ -70,13 +71,14 @@ class SurfaceFreezer {
* above the target surface) and then taking a snapshot and placing it over the target surface.
*
* @param startBounds The original bounds (on screen) of the surface we are snapshotting.
+ * @param relativePosition The related position of the snapshot surface to its parent.
*/
- void freeze(SurfaceControl.Transaction t, Rect startBounds) {
+ void freeze(SurfaceControl.Transaction t, Rect startBounds, Point relativePosition) {
mFreezeBounds.set(startBounds);
mLeash = SurfaceAnimator.createAnimationLeash(mAnimatable, mAnimatable.getSurfaceControl(),
t, ANIMATION_TYPE_SCREEN_ROTATION, startBounds.width(), startBounds.height(),
- startBounds.left, startBounds.top, false /* hidden */,
+ relativePosition.x, relativePosition.y, false /* hidden */,
mWmService.mTransactionFactory);
mAnimatable.onAnimationLeashCreated(t, mLeash);
@@ -123,6 +125,18 @@ class SurfaceFreezer {
}
}
+ void setLayer(SurfaceControl.Transaction t, int layer) {
+ if (mLeash != null) {
+ t.setLayer(mLeash, layer);
+ }
+ }
+
+ void setRelativeLayer(SurfaceControl.Transaction t, SurfaceControl relativeTo, int layer) {
+ if (mLeash != null) {
+ t.setRelativeLayer(mLeash, relativeTo, layer);
+ }
+ }
+
boolean hasLeash() {
return mLeash != null;
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 3f6708d1843c..c5362d38c613 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4809,10 +4809,6 @@ class Task extends TaskFragment {
notifyClients);
}, true /* traverseTopToBottom */);
- // Notify WM shell that task visibilities may have changed
- forAllTasks(task -> task.dispatchTaskInfoChangedIfNeeded(/* force */ false),
- true /* traverseTopToBottom */);
-
if (mTranslucentActivityWaiting != null &&
mUndrawnActivitiesBelowTopTranslucent.isEmpty()) {
// Nothing is getting drawn or everything was already visible, don't wait for
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index a257e902dc46..66f2dbc8ec09 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1336,12 +1336,11 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
if (mLaunchRootTasks.get(i).contains(windowingMode, activityType)) {
final Task launchRootTask = mLaunchRootTasks.get(i).task;
- // Return the focusable root task for improving the UX with staged split screen.
final TaskFragment adjacentTaskFragment = launchRootTask != null
? launchRootTask.getAdjacentTaskFragment() : null;
final Task adjacentRootTask =
adjacentTaskFragment != null ? adjacentTaskFragment.asTask() : null;
- if (adjacentRootTask != null && adjacentRootTask.isFocusedRootTaskOnDisplay()) {
+ if (sourceTask != null && sourceTask.getRootTask() == adjacentRootTask) {
return adjacentRootTask;
} else {
return launchRootTask;
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index f43cd7a80ede..9cc24e2b2120 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -261,7 +261,8 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
if (launchMode == WINDOWING_MODE_PINNED) {
if (DEBUG) appendLog("picture-in-picture");
} else if (!root.isResizeable()) {
- if (shouldLaunchUnresizableAppInFreeform(root, suggestedDisplayArea)) {
+ if (shouldLaunchUnresizableAppInFreeform(root, suggestedDisplayArea,
+ options.getLaunchWindowingMode())) {
launchMode = WINDOWING_MODE_FREEFORM;
if (outParams.mBounds.isEmpty()) {
getTaskBounds(root, suggestedDisplayArea, layout, launchMode,
@@ -617,7 +618,11 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
}
private boolean shouldLaunchUnresizableAppInFreeform(ActivityRecord activity,
- TaskDisplayArea displayArea) {
+ TaskDisplayArea displayArea, int launchWindowingMode) {
+ if (launchWindowingMode == WINDOWING_MODE_FULLSCREEN) {
+ // Do not launch the activity in freeform if it explicitly requested fullscreen mode.
+ return false;
+ }
if (!activity.supportsFreeformInDisplayArea(displayArea) || activity.isResizeable()) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 28beaf36d435..ccda126b3e95 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -688,6 +688,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
if (state != null) {
state.mOrganizer.onTaskVanished(task);
}
+ mLastSentTaskInfos.remove(task);
break;
case PendingTaskEvent.EVENT_INFO_CHANGED:
dispatchTaskInfoChanged(event.mTask, event.mForce);
diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
index 08758afcb0b2..073a508083f0 100644
--- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -21,7 +21,6 @@ import static com.android.server.wm.AnimationSpecProto.WINDOW;
import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_NONE;
-import android.annotation.ColorInt;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemClock;
@@ -86,12 +85,6 @@ public class WindowAnimationSpec implements AnimationSpec {
}
@Override
- @ColorInt
- public int getBackgroundColor() {
- return mAnimation.getBackgroundColor();
- }
-
- @Override
public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
final TmpValues tmp = mThreadLocalTmps.get();
tmp.transformation.clear();
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 54644151c630..2a8fa1086799 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2334,10 +2334,15 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
protected void setLayer(Transaction t, int layer) {
-
- // Route through surface animator to accommodate that our surface control might be
- // attached to the leash, and leash is attached to parent container.
- mSurfaceAnimator.setLayer(t, layer);
+ if (mSurfaceFreezer.hasLeash()) {
+ // When the freezer has created animation leash parent for the window, set the layer
+ // there instead.
+ mSurfaceFreezer.setLayer(t, layer);
+ } else {
+ // Route through surface animator to accommodate that our surface control might be
+ // attached to the leash, and leash is attached to parent container.
+ mSurfaceAnimator.setLayer(t, layer);
+ }
}
int getLastLayer() {
@@ -2345,10 +2350,15 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
-
- // Route through surface animator to accommodate that our surface control might be
- // attached to the leash, and leash is attached to parent container.
- mSurfaceAnimator.setRelativeLayer(t, relativeTo, layer);
+ if (mSurfaceFreezer.hasLeash()) {
+ // When the freezer has created animation leash parent for the window, set the layer
+ // there instead.
+ mSurfaceFreezer.setRelativeLayer(t, relativeTo, layer);
+ } else {
+ // Route through surface animator to accommodate that our surface control might be
+ // attached to the leash, and leash is attached to parent container.
+ mSurfaceAnimator.setRelativeLayer(t, relativeTo, layer);
+ }
}
protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
@@ -2613,11 +2623,20 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* 3. {@link ActivityRecord} is reparented into an organized {@link TaskFragment}.
*
* This shouldn't be called on other {@link WindowContainer} unless there is a valid use case.
+ *
+ * @param startBounds The original bounds (on screen) of the surface we are snapshotting.
+ * @param parentBounds The parent bounds (on screen) to calculate the animation surface
+ * position.
*/
- void initializeChangeTransition(Rect startBounds) {
+ void initializeChangeTransition(Rect startBounds, Rect parentBounds) {
mDisplayContent.prepareAppTransition(TRANSIT_CHANGE);
mDisplayContent.mChangingContainers.add(this);
- mSurfaceFreezer.freeze(getSyncTransaction(), startBounds);
+ mTmpPoint.set(startBounds.left - parentBounds.left, startBounds.top - parentBounds.top);
+ mSurfaceFreezer.freeze(getSyncTransaction(), startBounds, mTmpPoint);
+ }
+
+ void initializeChangeTransition(Rect startBounds) {
+ initializeChangeTransition(startBounds, getParent().getBounds());
}
ArraySet<WindowContainer> getAnimationSources() {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 4cc764ac33ca..69313810fa93 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -318,7 +318,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
* @param caller Info about the calling process.
*/
private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
- @Nullable Transition transition, @Nullable CallerInfo caller) {
+ @Nullable Transition transition, @NonNull CallerInfo caller) {
int effects = 0;
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
mService.deferWindowLayout();
@@ -540,7 +540,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
- @Nullable CallerInfo caller, @Nullable IBinder errorCallbackToken,
+ @NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,
@Nullable ITaskFragmentOrganizer organizer) {
final int type = hop.getType();
switch (type) {
@@ -628,11 +628,28 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final int taskId = launchOpts.getInt(
WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
- final SafeActivityOptions safeOptions = caller != null
- ? SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid)
- : SafeActivityOptions.fromBundle(launchOpts);
- mService.mTaskSupervisor.startActivityFromRecents(caller.mPid, caller.mUid,
- taskId, safeOptions);
+ final SafeActivityOptions safeOptions =
+ SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
+ final Integer[] starterResult = { null };
+ // startActivityFromRecents should not be called in lock.
+ mService.mH.post(() -> {
+ try {
+ starterResult[0] = mService.mTaskSupervisor.startActivityFromRecents(
+ caller.mPid, caller.mUid, taskId, safeOptions);
+ } catch (Throwable t) {
+ starterResult[0] = ActivityManager.START_CANCELED;
+ Slog.w(TAG, t);
+ }
+ synchronized (mGlobalLock) {
+ mGlobalLock.notifyAll();
+ }
+ });
+ while (starterResult[0] == null) {
+ try {
+ mGlobalLock.wait();
+ } catch (InterruptedException ignored) {
+ }
+ }
break;
case HIERARCHY_OP_TYPE_PENDING_INTENT:
String resolvedType = hop.getActivityIntent() != null
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 6eb2e8a2fd54..719d52c89209 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -264,7 +264,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
onConfigurationChanged(atm.getGlobalConfiguration());
- mAtm.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, mName);
+ mAtm.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, mInfo.packageName);
}
public void setPid(int pid) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6b4b0c94f657..c283ef07dce6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8414,17 +8414,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mDeviceAdminServiceController.startServiceForOwner(
admin.getPackageName(), userId, "set-device-owner");
- Slogf.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId);
+ Slogf.i(LOG_TAG, "Device owner set: %s on user %d", admin.flattenToShortString(),
+ userId);
if (mInjector.userManagerIsHeadlessSystemUserMode()) {
int currentForegroundUser = getCurrentForegroundUserId();
- Slogf.i(LOG_TAG, "setDeviceOwner(): setting " + admin
- + " as profile owner on user " + currentForegroundUser);
+ Slogf.i(LOG_TAG, "setDeviceOwner(): setting %s as profile owner on user %d",
+ admin.flattenToShortString(), currentForegroundUser);
// Sets profile owner on current foreground user since
// the human user will complete the DO setup workflow from there.
- manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin,
+ mInjector.binderWithCleanCallingIdentity(() -> manageUserUnchecked(
+ /* deviceOwner= */ admin, /* profileOwner= */ admin,
/* managedUser= */ currentForegroundUser, /* adminExtras= */ null,
- /* showDisclaimer= */ false);
+ /* showDisclaimer= */ false));
}
return true;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java
index bf97042d7b88..df19be4a9cfe 100644
--- a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java
@@ -31,8 +31,6 @@ import android.util.ArraySet;
import androidx.test.filters.SmallTest;
-import com.android.server.compat.overrides.AppCompatOverridesParser.PackageOverrides;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -183,115 +181,84 @@ public class AppCompatOverridesParserTest {
}
@Test
- public void parsePackageOverrides_emptyConfig_returnsEmpty() {
- PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
- "", /* versionCode= */ 0, /* changeIdsToSkip= */ emptySet());
+ public void parsePackageOverrides_emptyConfigNoOwnedChangeIds_returnsEmpty() {
+ Map<Long, PackageOverride> result = AppCompatOverridesParser.parsePackageOverrides(
+ /* configStr= */ "", /* versionCode= */ 0, /* changeIdsToSkip= */ emptySet());
- assertThat(result.overridesToAdd).isEmpty();
- assertThat(result.overridesToRemove).isEmpty();
+ assertThat(result).isEmpty();
}
@Test
public void parsePackageOverrides_configWithSingleOverride_returnsOverride() {
- PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
- "123:::true", /* versionCode= */ 5, /* changeIdsToSkip= */ emptySet());
+ Map<Long, PackageOverride> result = AppCompatOverridesParser.parsePackageOverrides(
+ /* configStr= */ "123:::true", /* versionCode= */ 5, /* changeIdsToSkip= */
+ emptySet());
- assertThat(result.overridesToAdd).hasSize(1);
- assertThat(result.overridesToAdd.get(123L)).isEqualTo(
+ assertThat(result).hasSize(1);
+ assertThat(result.get(123L)).isEqualTo(
new PackageOverride.Builder().setEnabled(true).build());
}
@Test
- public void parsePackageOverrides_configWithMultipleOverridesToAdd_returnsOverrides() {
- PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
- "910:3:4:false,78:10::false,12:::false,34:1:2:true,34:10::true,56::2:true,"
- + "56:3:4:false,34:4:8:true,78:6:7:true,910:5::true,1112::5:true,"
- + "56:6::true,1112:6:7:false", /* versionCode= */
+ public void parsePackageOverrides_configWithMultipleOverrides_returnsOverrides() {
+ Map<Long, PackageOverride> result = AppCompatOverridesParser.parsePackageOverrides(
+ /* configStr= */ "910:3:4:false,78:10::false,12:::false,34:1:2:true,34:10::true,"
+ + "56::2:true,56:3:4:false,34:4:8:true,78:6:7:true,910:5::true,"
+ + "1112::5:true,56:6::true,1112:6:7:false", /* versionCode= */
5, /* changeIdsToSkip= */ emptySet());
- assertThat(result.overridesToAdd).hasSize(6);
- assertThat(result.overridesToAdd.get(12L)).isEqualTo(
+ assertThat(result).hasSize(6);
+ assertThat(result.get(12L)).isEqualTo(
new PackageOverride.Builder().setEnabled(false).build());
- assertThat(result.overridesToAdd.get(34L)).isEqualTo(
+ assertThat(result.get(34L)).isEqualTo(
new PackageOverride.Builder().setMinVersionCode(4).setMaxVersionCode(8).setEnabled(
true).build());
- assertThat(result.overridesToAdd.get(56L)).isEqualTo(
+ assertThat(result.get(56L)).isEqualTo(
new PackageOverride.Builder().setMinVersionCode(3).setMaxVersionCode(4).setEnabled(
false).build());
- assertThat(result.overridesToAdd.get(78L)).isEqualTo(
+ assertThat(result.get(78L)).isEqualTo(
new PackageOverride.Builder().setMinVersionCode(6).setMaxVersionCode(7).setEnabled(
true).build());
- assertThat(result.overridesToAdd.get(910L)).isEqualTo(
+ assertThat(result.get(910L)).isEqualTo(
new PackageOverride.Builder().setMinVersionCode(5).setEnabled(true).build());
- assertThat(result.overridesToAdd.get(1112L)).isEqualTo(
+ assertThat(result.get(1112L)).isEqualTo(
new PackageOverride.Builder().setMaxVersionCode(5).setEnabled(true).build());
- assertThat(result.overridesToRemove).isEmpty();
- }
-
- @Test
- public void parsePackageOverrides_configWithMultipleOverridesToRemove_returnsOverrides() {
- PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
- "12:::,34:1:2:", /* versionCode= */ 5, /* changeIdsToSkip= */ emptySet());
-
- assertThat(result.overridesToRemove).containsExactly(12L, 34L);
- assertThat(result.overridesToAdd).isEmpty();
- }
-
- @Test
- public void parsePackageOverrides_configWithBothOverridesToAddAndRemove_returnsOverrides() {
- // Note that change 56 is both added and removed, therefore it will only be removed.
- PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
- "56:::,12:::true,34:::,56:3:7:true", /* versionCode= */ 5, /* changeIdsToSkip= */
- emptySet());
-
- assertThat(result.overridesToAdd).hasSize(1);
- assertThat(result.overridesToAdd.get(12L)).isEqualTo(
- new PackageOverride.Builder().setEnabled(true).build());
- assertThat(result.overridesToRemove).containsExactly(34L, 56L);
}
@Test
public void parsePackageOverrides_changeIdsToSkipSpecified_returnsWithoutChangeIdsToSkip() {
- ArraySet<Long> changeIdsToSkip = new ArraySet<>();
- changeIdsToSkip.add(34L);
- changeIdsToSkip.add(56L);
- changeIdsToSkip.add(910L);
- PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
- "12:::true,34:::,56:3:7:true,78:::", /* versionCode= */ 5, changeIdsToSkip);
-
- assertThat(result.overridesToAdd).hasSize(1);
- assertThat(result.overridesToAdd.get(12L)).isEqualTo(
+ ArraySet<Long> changeIdsToSkip = new ArraySet<>(Arrays.asList(34L, 56L));
+ Map<Long, PackageOverride> result = AppCompatOverridesParser.parsePackageOverrides(
+ /* configStr= */ "12:::true,56:3:7:true", /* versionCode= */ 5, changeIdsToSkip);
+
+ assertThat(result).hasSize(1);
+ assertThat(result.get(12L)).isEqualTo(
new PackageOverride.Builder().setEnabled(true).build());
- assertThat(result.overridesToRemove).containsExactly(78L);
}
@Test
public void parsePackageOverrides_changeIdsToSkipContainsAllIds_returnsEmpty() {
- ArraySet<Long> changeIdsToSkip = new ArraySet<>();
- changeIdsToSkip.add(12L);
- changeIdsToSkip.add(34L);
- PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
- "12:::true,34:::", /* versionCode= */ 5, changeIdsToSkip);
-
- assertThat(result.overridesToAdd).isEmpty();
- assertThat(result.overridesToRemove).isEmpty();
+ ArraySet<Long> changeIdsToSkip = new ArraySet<>(Arrays.asList(12L, 34L));
+ Map<Long, PackageOverride> result = AppCompatOverridesParser.parsePackageOverrides(
+ /* configStr= */ "12:::true", /* versionCode= */ 5, changeIdsToSkip);
+
+ assertThat(result).isEmpty();
}
@Test
public void parsePackageOverrides_someOverridesAreInvalid_returnsWithoutInvalidOverrides() {
// We add a valid entry before and after the invalid ones to make sure they are applied.
- PackageOverrides result = AppCompatOverridesParser.parsePackageOverrides(/* configStr= */
- "12:::True,56:1:2:FALSE,56:3:true,78:4:8:true:,C1:::true,910:::no,"
- + "1112:1:ten:true,1112:one:10:true,,1314:7:3:false,34:one:ten:",
+ Map<Long, PackageOverride> result = AppCompatOverridesParser.parsePackageOverrides(
+ /* configStr= */ "12:::True,56:1:2:FALSE,56:3:true,78:4:8:true:,C1:::true,910:::no,"
+ + "1112:1:ten:true,1112:one:10:true,,1314:7:3:false,34:::",
/* versionCode= */ 5, /* changeIdsToSkip= */ emptySet());
- assertThat(result.overridesToAdd).hasSize(2);
- assertThat(result.overridesToAdd.get(12L)).isEqualTo(
+ assertThat(result).hasSize(2);
+ assertThat(result.get(12L)).isEqualTo(
new PackageOverride.Builder().setEnabled(true).build());
- assertThat(result.overridesToAdd.get(56L)).isEqualTo(
+ assertThat(result.get(56L)).isEqualTo(
new PackageOverride.Builder().setMinVersionCode(1).setMaxVersionCode(2).setEnabled(
false).build());
- assertThat(result.overridesToRemove).containsExactly(34L);
}
private static ApplicationInfo createAppInfo(String packageName) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java
index 312927206a80..007191f02631 100644
--- a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java
@@ -95,7 +95,6 @@ public class AppCompatOverridesServiceTest {
private static final String PACKAGE_2 = "com.android.test2";
private static final String PACKAGE_3 = "com.android.test3";
private static final String PACKAGE_4 = "com.android.test4";
- private static final String PACKAGE_5 = "com.android.test5";
private MockContext mMockContext;
private BroadcastReceiver mPackageReceiver;
@@ -157,16 +156,14 @@ public class AppCompatOverridesServiceTest {
mockGetApplicationInfoNotInstalled(PACKAGE_2);
mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 10);
mockGetApplicationInfo(PACKAGE_4, /* versionCode= */ 1);
- mockGetApplicationInfo(PACKAGE_5, /* versionCode= */ 1);
mService.registerDeviceConfigListeners();
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
- .setString(PACKAGE_1, "123:::true,456::1:false,456:2::true")
+ .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789")
+ .setString(PACKAGE_1, "123:::true,456::1:false,456:2::true,789:::false")
.setString(PACKAGE_2, "123:::true")
- .setString(PACKAGE_3, "123:1:9:true,123:10:11:false,123:11::true,456:::")
- .setString(PACKAGE_4, "")
- .setString(PACKAGE_5, "123:::,789:::")
- .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789").build());
+ .setString(PACKAGE_3, "123:1:9:true,123:10:11:false,123:11::true")
+ .setString(PACKAGE_4, "").build());
Map<Long, PackageOverride> addedOverrides;
// Package 1
@@ -175,11 +172,13 @@ public class AppCompatOverridesServiceTest {
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
addedOverrides = mOverridesToAddConfigCaptor.getValue().overrides;
- assertThat(addedOverrides).hasSize(2);
+ assertThat(addedOverrides).hasSize(3);
assertThat(addedOverrides.get(123L)).isEqualTo(
new PackageOverride.Builder().setEnabled(true).build());
assertThat(addedOverrides.get(456L)).isEqualTo(
new PackageOverride.Builder().setMinVersionCode(2).setEnabled(true).build());
+ assertThat(addedOverrides.get(789L)).isEqualTo(
+ new PackageOverride.Builder().setEnabled(false).build());
// Package 2
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
@@ -195,24 +194,37 @@ public class AppCompatOverridesServiceTest {
assertThat(addedOverrides.get(123L)).isEqualTo(
new PackageOverride.Builder().setMinVersionCode(10).setMaxVersionCode(
11).setEnabled(false).build());
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L);
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L, 789L);
// Package 4
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_4));
- verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4));
- // Package 5
- verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
- any(CompatibilityOverrideConfig.class), eq(PACKAGE_5));
verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_5));
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 789L);
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_4));
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L,
+ 789L);
+ }
+
+ @Test
+ public void onPropertiesChanged_ownedChangeIdsFlagNotSet_onlyAddsOverrides()
+ throws Exception {
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+
+ mService.registerDeviceConfigListeners();
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(PACKAGE_1, "123:::true").build());
+
+ verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
+ eq(PACKAGE_1));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+ assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(123L);
}
@Test
public void onPropertiesChanged_removeOverridesFlagSetBefore_skipsOverridesToRemove()
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789")
.setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=123:456," + PACKAGE_2 + "=123")
.setString(PACKAGE_1, "123:::true")
.setString(PACKAGE_4, "123:::true").build());
@@ -222,7 +234,7 @@ public class AppCompatOverridesServiceTest {
mService.registerDeviceConfigListeners();
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
- .setString(PACKAGE_1, "123:::true,456:::,789:::false")
+ .setString(PACKAGE_1, "123:::true,789:::false")
.setString(PACKAGE_2, "123:::true")
.setString(PACKAGE_3, "456:::true").build());
@@ -235,14 +247,16 @@ public class AppCompatOverridesServiceTest {
// Package 2
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
- verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L, 789L);
// Package 3
verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
eq(PACKAGE_3));
- verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_3));
assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(456L);
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 789L);
// Package 4 (not applied because it hasn't changed after the listener was added)
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_4));
@@ -253,27 +267,44 @@ public class AppCompatOverridesServiceTest {
@Test
public void onPropertiesChanged_removeOverridesFlagChangedNoPackageOverridesFlags_removesOnly()
throws Exception {
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789")
+ .setString(PACKAGE_1, "")
+ .setString(PACKAGE_2, "").build());
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+ mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0);
+
mService.registerDeviceConfigListeners();
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(FLAG_REMOVE_OVERRIDES,
- PACKAGE_1 + "=123:456," + PACKAGE_2 + "=789").build());
+ PACKAGE_1 + "=123:456," + PACKAGE_2 + "=*").build());
// Package 1
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
+ verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L);
+ List<CompatibilityOverridesToRemoveConfig> configs =
+ mOverridesToRemoveConfigCaptor.getAllValues();
+ assertThat(configs.size()).isAtLeast(2);
+ assertThat(configs.get(configs.size() - 2).changeIds).containsExactly(123L, 456L);
+ assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(789L);
// Package 2
+ verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
+ any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(789L);
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L,
+ 789L);
}
@Test
public void onPropertiesChanged_removeOverridesFlagAndSomePackageOverrideFlagsChanged_ok()
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_OWNED_CHANGE_IDS, "123,456,789")
.setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=123:456")
- .setString(PACKAGE_1, "123:::true,456:::,789:::false")
+ .setString(PACKAGE_1, "123:::true,789:::false")
.setString(PACKAGE_3, "456:::false,789:::true").build());
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0);
@@ -282,7 +313,7 @@ public class AppCompatOverridesServiceTest {
mService.registerDeviceConfigListeners();
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(FLAG_REMOVE_OVERRIDES, PACKAGE_2 + "=123," + PACKAGE_3 + "=789")
- .setString(PACKAGE_2, "123:::true,456:::").build());
+ .setString(PACKAGE_2, "123:::true").build());
// Package 1
verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
@@ -301,14 +332,17 @@ public class AppCompatOverridesServiceTest {
mOverridesToRemoveConfigCaptor.getAllValues();
assertThat(configs.size()).isAtLeast(2);
assertThat(configs.get(configs.size() - 2).changeIds).containsExactly(123L);
- assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(456L);
+ assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(456L, 789L);
// Package 3
verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
eq(PACKAGE_3));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_3));
assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(456L);
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(789L);
+ configs = mOverridesToRemoveConfigCaptor.getAllValues();
+ assertThat(configs.size()).isAtLeast(2);
+ assertThat(configs.get(configs.size() - 2).changeIds).containsExactly(789L);
+ assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(123L);
}
@Test
@@ -338,9 +372,10 @@ public class AppCompatOverridesServiceTest {
// Package 2
verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
eq(PACKAGE_2));
- verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2));
+ verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
+ mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(123L);
+ assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L, 789L);
// Package 3
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_3));
@@ -362,10 +397,11 @@ public class AppCompatOverridesServiceTest {
mService.registerDeviceConfigListeners();
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
- .setString(PACKAGE_1, "123:::true,456:::")
- .setString(PACKAGE_2, "123:::true,456:::")
- .setString(PACKAGE_3, "123:::true,456:::")
- .setString(PACKAGE_4, "123:::true,456:::").build());
+ .setString(FLAG_OWNED_CHANGE_IDS, "123,456")
+ .setString(PACKAGE_1, "123:::true")
+ .setString(PACKAGE_2, "123:::true")
+ .setString(PACKAGE_3, "123:::true")
+ .setString(PACKAGE_4, "123:::true").build());
// Package 1
verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class),
@@ -478,12 +514,16 @@ public class AppCompatOverridesServiceTest {
@Test
public void packageReceiver_packageAddedIntent_appliesOverridesFromAllNamespaces()
throws Exception {
+ // We're adding the owned_change_ids flag to make sure it's ignored.
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
- .setString(PACKAGE_1, "101:::true,103:::")
+ .setString(FLAG_OWNED_CHANGE_IDS, "101,102,103")
+ .setString(PACKAGE_1, "101:::true")
.setString(PACKAGE_2, "102:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
+ .setString(FLAG_OWNED_CHANGE_IDS, "201,202,203")
.setString(PACKAGE_3, "201:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
+ .setString(FLAG_OWNED_CHANGE_IDS, "301,302")
.setString(PACKAGE_1, "301:::true,302:::false")
.setString(PACKAGE_2, "302:::false").build());
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
@@ -493,19 +533,18 @@ public class AppCompatOverridesServiceTest {
verify(mPlatformCompat, times(2)).putOverridesOnReleaseBuilds(
mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
List<CompatibilityOverrideConfig> configs = mOverridesToAddConfigCaptor.getAllValues();
assertThat(configs.get(0).overrides.keySet()).containsExactly(101L);
assertThat(configs.get(1).overrides.keySet()).containsExactly(301L, 302L);
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(103L);
}
@Test
public void packageReceiver_packageChangedIntent_appliesOverrides()
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
- .setString(PACKAGE_1, "101:::true,103:::").build());
+ .setString(PACKAGE_1, "101:::true,103:::false").build());
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
mPackageReceiver.onReceive(mMockContext,
@@ -513,10 +552,10 @@ public class AppCompatOverridesServiceTest {
verify(mPlatformCompat).putOverridesOnReleaseBuilds(
mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
- assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(101L);
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(103L);
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
+ assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(101L,
+ 103L);
}
@Test
@@ -524,13 +563,13 @@ public class AppCompatOverridesServiceTest {
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=103," + PACKAGE_2 + "=101")
- .setString(PACKAGE_1, "101:::true,103:::")
+ .setString(PACKAGE_1, "101:::true,103:::false")
.setString(PACKAGE_2, "102:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(PACKAGE_1, "201:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
.setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=301," + PACKAGE_3 + "=302")
- .setString(PACKAGE_1, "301:::true,302:::false,303:::")
+ .setString(PACKAGE_1, "301:::true,302:::false,303:::true")
.setString(PACKAGE_3, "302:::false").build());
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
@@ -539,13 +578,12 @@ public class AppCompatOverridesServiceTest {
verify(mPlatformCompat, times(3)).putOverridesOnReleaseBuilds(
mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
+ verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
List<CompatibilityOverrideConfig> configs = mOverridesToAddConfigCaptor.getAllValues();
assertThat(configs.get(0).overrides.keySet()).containsExactly(101L);
assertThat(configs.get(1).overrides.keySet()).containsExactly(201L);
- assertThat(configs.get(2).overrides.keySet()).containsExactly(302L);
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(303L);
+ assertThat(configs.get(2).overrides.keySet()).containsExactly(302L, 303L);
}
@Test
@@ -573,7 +611,7 @@ public class AppCompatOverridesServiceTest {
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(FLAG_OWNED_CHANGE_IDS, "101,102,103")
- .setString(PACKAGE_1, "101:::true,103:::").build());
+ .setString(PACKAGE_1, "101:::true,103:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(FLAG_OWNED_CHANGE_IDS, "201,202")
.setString(PACKAGE_1, "202:::false").build());
@@ -593,14 +631,14 @@ public class AppCompatOverridesServiceTest {
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(FLAG_OWNED_CHANGE_IDS, "101,102,103")
- .setString(PACKAGE_1, "101:::true,103:::")
+ .setString(PACKAGE_1, "101:::true,103:::false")
.setString(PACKAGE_2, "102:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(FLAG_OWNED_CHANGE_IDS, "201")
.setString(PACKAGE_3, "201:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
.setString(FLAG_OWNED_CHANGE_IDS, "301,302")
- .setString(PACKAGE_1, "302:::")
+ .setString(PACKAGE_1, "302:::false")
.setString(PACKAGE_2, "301:::true").build());
mockGetApplicationInfoNotInstalled(PACKAGE_1);
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 4564296810ff..0dd5c61121db 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -20,6 +20,8 @@ import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REF
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_SUNLIGHT;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_HDR;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE;
@@ -1408,6 +1410,12 @@ public class DisplayModeDirectorTest {
public void testHbmVoting_forHdr() {
DisplayModeDirector director =
createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
+ final int hbmRefreshRate = 72;
+
+ // Specify limitation before starting DisplayModeDirector to avoid waiting on property
+ // propagation
+ mInjector.getDeviceConfig().setRefreshRateInHbmHdr(hbmRefreshRate);
+
director.start(createMockSensorManager());
ArgumentCaptor<DisplayListener> captor =
@@ -1432,7 +1440,7 @@ public class DisplayModeDirectorTest {
new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR));
listener.onDisplayChanged(DISPLAY_ID);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
- assertVoteForRefreshRate(vote, 60.f);
+ assertVoteForRefreshRate(vote, hbmRefreshRate);
// Turn off HBM
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
@@ -1443,6 +1451,44 @@ public class DisplayModeDirectorTest {
}
@Test
+ public void testHbmObserverGetsUpdatedRefreshRateInHbmSunlight() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0);
+
+ final int initialRefreshRate = 60;
+ mInjector.getDeviceConfig().setRefreshRateInHbmSunlight(initialRefreshRate);
+ director.start(createMockSensorManager());
+ assertThat(director.getHbmObserver().getRefreshRateInHbmSunlight())
+ .isEqualTo(initialRefreshRate);
+
+ final int updatedRefreshRate = 90;
+ mInjector.getDeviceConfig().setRefreshRateInHbmSunlight(updatedRefreshRate);
+ // Need to wait for the property change to propagate to the main thread.
+ waitForIdleSync();
+ assertThat(director.getHbmObserver().getRefreshRateInHbmSunlight())
+ .isEqualTo(updatedRefreshRate);
+ }
+
+ @Test
+ public void testHbmObserverGetsUpdatedRefreshRateInHbmHdr() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0);
+
+ final int initialRefreshRate = 60;
+ mInjector.getDeviceConfig().setRefreshRateInHbmHdr(initialRefreshRate);
+ director.start(createMockSensorManager());
+ assertThat(director.getHbmObserver().getRefreshRateInHbmHdr())
+ .isEqualTo(initialRefreshRate);
+
+ final int updatedRefreshRate = 90;
+ mInjector.getDeviceConfig().setRefreshRateInHbmHdr(updatedRefreshRate);
+ // Need to wait for the property change to propagate to the main thread.
+ waitForIdleSync();
+ assertThat(director.getHbmObserver().getRefreshRateInHbmHdr())
+ .isEqualTo(updatedRefreshRate);
+ }
+
+ @Test
public void testHbmVoting_forSunlight() {
DisplayModeDirector director =
createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
@@ -1455,11 +1501,12 @@ public class DisplayModeDirectorTest {
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
DisplayListener listener = captor.getValue();
+ final int initialRefreshRate = 60;
// Specify Limitation
when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)).thenReturn(
List.of(new RefreshRateLimitation(
DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE,
- 60.f, 60.f)));
+ initialRefreshRate, initialRefreshRate)));
// Verify that there is no HBM vote initially
Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
@@ -1470,7 +1517,39 @@ public class DisplayModeDirectorTest {
new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT));
listener.onDisplayChanged(DISPLAY_ID);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
- assertVoteForRefreshRate(vote, 60.f);
+ assertVoteForRefreshRate(vote, initialRefreshRate);
+
+ // Change refresh rate vote value through DeviceConfig, ensure it takes precedence
+ final int updatedRefreshRate = 90;
+ mInjector.getDeviceConfig().setRefreshRateInHbmSunlight(updatedRefreshRate);
+ // Need to wait for the property change to propagate to the main thread.
+ waitForIdleSync();
+ assertThat(director.getHbmObserver().getRefreshRateInHbmSunlight())
+ .isEqualTo(updatedRefreshRate);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertVoteForRefreshRate(vote, updatedRefreshRate);
+
+ // Turn off HBM
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn HBM on again and ensure the updated vote value stuck
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertVoteForRefreshRate(vote, updatedRefreshRate);
+
+ // Reset DeviceConfig refresh rate, ensure vote falls back to the initial value
+ mInjector.getDeviceConfig().setRefreshRateInHbmSunlight(0);
+ // Need to wait for the property change to propagate to the main thread.
+ waitForIdleSync();
+ assertThat(director.getHbmObserver().getRefreshRateInHbmSunlight()).isEqualTo(0);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertVoteForRefreshRate(vote, initialRefreshRate);
// Turn off HBM
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
@@ -1518,6 +1597,63 @@ public class DisplayModeDirectorTest {
assertNull(vote);
}
+ private void setHbmAndAssertRefreshRate(
+ DisplayModeDirector director, DisplayListener listener, int mode, float rr) {
+ when(mInjector.getBrightnessInfo(DISPLAY_ID))
+ .thenReturn(new BrightnessInfo(1.0f, 0.0f, 1.0f, mode));
+ listener.onDisplayChanged(DISPLAY_ID);
+
+ final Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ if (Float.isNaN(rr)) {
+ assertNull(vote);
+ } else {
+ assertVoteForRefreshRate(vote, rr);
+ }
+ }
+
+ @Test
+ public void testHbmVoting_forSunlightAndHdr() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
+
+ // Specify HDR limitation before starting DisplayModeDirector to avoid waiting on property
+ // propagation
+ final int hdrRr = 60;
+ mInjector.getDeviceConfig().setRefreshRateInHbmHdr(hdrRr);
+ director.start(createMockSensorManager());
+
+ ArgumentCaptor<DisplayListener> captor = ArgumentCaptor.forClass(DisplayListener.class);
+ verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
+ eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
+ | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
+ DisplayListener listener = captor.getValue();
+
+ // Specify Sunlight limitations
+ final float sunlightRr = 90.0f;
+ when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID))
+ .thenReturn(List.of(new RefreshRateLimitation(
+ DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, sunlightRr,
+ sunlightRr)));
+
+ // Verify that there is no HBM vote initially
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Verify all state transitions
+ setHbmAndAssertRefreshRate(
+ director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, sunlightRr);
+ setHbmAndAssertRefreshRate(
+ director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, hdrRr);
+ setHbmAndAssertRefreshRate(
+ director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, Float.NaN);
+ setHbmAndAssertRefreshRate(
+ director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, hdrRr);
+ setHbmAndAssertRefreshRate(
+ director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, sunlightRr);
+ setHbmAndAssertRefreshRate(
+ director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, Float.NaN);
+ }
+
@Test
public void testHbmVoting_RemovedDisplay() {
DisplayModeDirector director =
@@ -1622,6 +1758,16 @@ public class DisplayModeDirectorTest {
String.valueOf(fps));
}
+ void setRefreshRateInHbmSunlight(int fps) {
+ putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ KEY_REFRESH_RATE_IN_HBM_SUNLIGHT, String.valueOf(fps));
+ }
+
+ void setRefreshRateInHbmHdr(int fps) {
+ putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ KEY_REFRESH_RATE_IN_HBM_HDR, String.valueOf(fps));
+ }
+
void setLowDisplayBrightnessThresholds(int[] brightnessThresholds) {
String thresholds = toPropertyValue(brightnessThresholds);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 89ae5ed9b425..08312ef0b865 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -341,7 +341,8 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
verify(mMockTransaction).setWindowCrop(
mMockLeash, app.startBounds.width(), app.startBounds.height());
verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
- verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, -1, -1);
+ verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, app.startBounds.width(),
+ app.startBounds.height());
finishedCaptor.getValue().onAnimationFinished();
verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),
@@ -394,7 +395,63 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
verify(mMockTransaction).setWindowCrop(
mMockLeash, app.startBounds.width(), app.startBounds.height());
verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
- verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, -1, -1);
+ verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, app.startBounds.width(),
+ app.startBounds.height());
+
+ finishedCaptor.getValue().onAnimationFinished();
+ verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),
+ eq(record.mAdapter));
+ verify(mThumbnailFinishedCallback).onAnimationFinished(
+ eq(ANIMATION_TYPE_WINDOW_ANIMATION), eq(record.mThumbnailAdapter));
+ } finally {
+ mDisplayContent.mChangingContainers.clear();
+ }
+ }
+
+ @Test
+ public void testChangeToDifferentPosition() throws Exception {
+ final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+ mDisplayContent.mChangingContainers.add(win.mActivityRecord);
+ try {
+ final RemoteAnimationRecord record = mController.createRemoteAnimationRecord(
+ win.mActivityRecord, new Point(100, 100), null, new Rect(150, 150, 400, 400),
+ new Rect(50, 100, 150, 150));
+ assertNotNull(record.mThumbnailAdapter);
+ ((AnimationAdapter) record.mAdapter)
+ .startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION,
+ mFinishedCallback);
+ ((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
+ mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback);
+ mController.goodToGo(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+ ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+ final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
+ ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+ final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
+ ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+ final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
+ ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
+ verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE),
+ appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
+ finishedCaptor.capture());
+ assertEquals(1, appsCaptor.getValue().length);
+ final RemoteAnimationTarget app = appsCaptor.getValue()[0];
+ assertEquals(RemoteAnimationTarget.MODE_CHANGING, app.mode);
+ assertEquals(new Point(100, 100), app.position);
+ assertEquals(new Rect(150, 150, 400, 400), app.sourceContainerBounds);
+ assertEquals(new Rect(50, 100, 150, 150), app.startBounds);
+ assertEquals(mMockLeash, app.leash);
+ assertEquals(mMockThumbnailLeash, app.startLeash);
+ assertEquals(false, app.isTranslucent);
+ verify(mMockTransaction).setPosition(
+ mMockLeash, app.position.x + app.startBounds.left - app.screenSpaceBounds.left,
+ app.position.y + app.startBounds.top - app.screenSpaceBounds.top);
+ verify(mMockTransaction).setWindowCrop(
+ mMockLeash, app.startBounds.width(), app.startBounds.height());
+ verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
+ verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, app.startBounds.width(),
+ app.startBounds.height());
finishedCaptor.getValue().onAnimationFinished();
verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 00f3d8b874f7..68053eb324b2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -1071,6 +1071,41 @@ public class WindowContainerTests extends WindowTestsBase {
verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */);
}
+ @Test
+ public void testAssignAnimationLayer() {
+ final WindowContainer container = new WindowContainer(mWm);
+ container.mSurfaceControl = mock(SurfaceControl.class);
+ final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator;
+ final SurfaceFreezer surfaceFreezer = container.mSurfaceFreezer;
+ final SurfaceControl relativeParent = mock(SurfaceControl.class);
+ final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+ spyOn(container);
+ spyOn(surfaceAnimator);
+ spyOn(surfaceFreezer);
+
+ container.setLayer(t, 1);
+ container.setRelativeLayer(t, relativeParent, 2);
+
+ // Set through surfaceAnimator if surfaceFreezer doesn't have leash.
+ verify(surfaceAnimator).setLayer(t, 1);
+ verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 2);
+ verify(surfaceFreezer, never()).setLayer(any(), anyInt());
+ verify(surfaceFreezer, never()).setRelativeLayer(any(), any(), anyInt());
+
+ clearInvocations(surfaceAnimator);
+ clearInvocations(surfaceFreezer);
+ doReturn(true).when(surfaceFreezer).hasLeash();
+
+ container.setLayer(t, 1);
+ container.setRelativeLayer(t, relativeParent, 2);
+
+ // Set through surfaceFreezer if surfaceFreezer has leash.
+ verify(surfaceFreezer).setLayer(t, 1);
+ verify(surfaceFreezer).setRelativeLayer(t, relativeParent, 2);
+ verify(surfaceAnimator, never()).setLayer(any(), anyInt());
+ verify(surfaceAnimator, never()).setRelativeLayer(any(), any(), anyInt());
+ }
+
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
private final int mLayer;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 9ea2b7b12ad0..8445ed4884e2 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -167,6 +167,16 @@ public class VoiceInteractionManagerService extends SystemService {
public void onStart() {
publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub);
publishLocalService(VoiceInteractionManagerInternal.class, new LocalService());
+ mAmInternal.setVoiceInteractionManagerProvider(
+ new ActivityManagerInternal.VoiceInteractionManagerProvider() {
+ @Override
+ public void notifyActivityEventChanged() {
+ if (DEBUG) {
+ Slog.d(TAG, "call notifyActivityEventChanged");
+ }
+ mServiceStub.notifyActivityEventChanged();
+ }
+ });
}
@Override
@@ -386,6 +396,14 @@ public class VoiceInteractionManagerService extends SystemService {
return mImpl.supportsLocalVoiceInteraction();
}
+ void notifyActivityEventChanged() {
+ synchronized (this) {
+ if (mImpl == null) return;
+
+ Binder.withCleanCallingIdentity(() -> mImpl.notifyActivityEventChangedLocked());
+ }
+ }
+
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
@@ -1109,6 +1127,40 @@ public class VoiceInteractionManagerService extends SystemService {
}
}
+ @Override
+ public void startListeningVisibleActivityChanged(@NonNull IBinder token) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "startListeningVisibleActivityChanged without running"
+ + " voice interaction service");
+ return;
+ }
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mImpl.startListeningVisibleActivityChangedLocked(token);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
+ @Override
+ public void stopListeningVisibleActivityChanged(@NonNull IBinder token) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "stopListeningVisibleActivityChanged without running"
+ + " voice interaction service");
+ return;
+ }
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mImpl.stopListeningVisibleActivityChangedLocked(token);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
//----------------- Hotword Detection/Validation APIs --------------------------------//
@Override
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 558a9ac9298e..52c5b6bbc239 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -414,6 +414,44 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
return mInfo.getSupportsLocalInteraction();
}
+ public void startListeningVisibleActivityChangedLocked(@NonNull IBinder token) {
+ if (DEBUG) {
+ Slog.d(TAG, "startListeningVisibleActivityChangedLocked: token=" + token);
+ }
+ if (mActiveSession == null || token != mActiveSession.mToken) {
+ Slog.w(TAG, "startListeningVisibleActivityChangedLocked does not match"
+ + " active session");
+ return;
+ }
+ mActiveSession.startListeningVisibleActivityChangedLocked();
+ }
+
+ public void stopListeningVisibleActivityChangedLocked(@NonNull IBinder token) {
+ if (DEBUG) {
+ Slog.d(TAG, "stopListeningVisibleActivityChangedLocked: token=" + token);
+ }
+ if (mActiveSession == null || token != mActiveSession.mToken) {
+ Slog.w(TAG, "stopListeningVisibleActivityChangedLocked does not match"
+ + " active session");
+ return;
+ }
+ mActiveSession.stopListeningVisibleActivityChangedLocked();
+ }
+
+ public void notifyActivityEventChangedLocked() {
+ if (DEBUG) {
+ Slog.d(TAG, "notifyActivityEventChangedLocked");
+ }
+ if (mActiveSession == null || !mActiveSession.mShown) {
+ if (DEBUG) {
+ Slog.d(TAG, "notifyActivityEventChangedLocked not allowed on no session or"
+ + " hidden session");
+ }
+ return;
+ }
+ mActiveSession.notifyActivityEventChangedLocked();
+ }
+
public void updateStateLocked(
@NonNull Identity voiceInteractorIdentity,
@Nullable PersistableBundle options,
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 08e9703124ab..90ccec852e1e 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -56,6 +56,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.IVoiceInteractionSessionService;
+import android.service.voice.VisibleActivityInfo;
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionSession;
import android.util.Slog;
@@ -71,16 +72,20 @@ import com.android.server.am.AssistDataRequester.AssistDataRequesterCallbacks;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.wm.ActivityAssistInfo;
+import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.PrintWriter;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
final class VoiceInteractionSessionConnection implements ServiceConnection,
AssistDataRequesterCallbacks {
static final String TAG = "VoiceInteractionServiceManager";
+ static final boolean DEBUG = false;
static final int POWER_BOOST_TIMEOUT_MS = Integer.parseInt(
System.getProperty("vendor.powerhal.interaction.max", "200"));
static final int BOOST_TIMEOUT_MS = 300;
@@ -114,6 +119,10 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
ArrayList<IVoiceInteractionSessionShowCallback> mPendingShowCallbacks = new ArrayList<>();
private List<ActivityAssistInfo> mPendingHandleAssistWithoutData = new ArrayList<>();
AssistDataRequester mAssistDataRequester;
+ private boolean mListeningVisibleActivity;
+ private final ScheduledExecutorService mScheduledExecutorService =
+ Executors.newSingleThreadScheduledExecutor();
+ private final List<VisibleActivityInfo> mVisibleActivityInfos = new ArrayList<>();
private final PowerManagerInternal mPowerManagerInternal;
private PowerBoostSetter mSetPowerBoostRunnable;
private final Handler mFgHandler;
@@ -496,6 +505,8 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
}
public void cancelLocked(boolean finishTask) {
+ mListeningVisibleActivity = false;
+ mVisibleActivityInfos.clear();
hideLocked();
mCanceled = true;
if (mBound) {
@@ -569,6 +580,156 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
mPendingShowCallbacks.clear();
}
+ void startListeningVisibleActivityChangedLocked() {
+ if (DEBUG) {
+ Slog.d(TAG, "startListeningVisibleActivityChangedLocked");
+ }
+ mListeningVisibleActivity = true;
+ mVisibleActivityInfos.clear();
+
+ mScheduledExecutorService.execute(() -> {
+ if (DEBUG) {
+ Slog.d(TAG, "call updateVisibleActivitiesLocked from enable listening");
+ }
+ synchronized (mLock) {
+ updateVisibleActivitiesLocked();
+ }
+ });
+ }
+
+ void stopListeningVisibleActivityChangedLocked() {
+ if (DEBUG) {
+ Slog.d(TAG, "stopListeningVisibleActivityChangedLocked");
+ }
+ mListeningVisibleActivity = false;
+ mVisibleActivityInfos.clear();
+ }
+
+ void notifyActivityEventChangedLocked() {
+ if (DEBUG) {
+ Slog.d(TAG, "notifyActivityEventChangedLocked");
+ }
+ if (!mListeningVisibleActivity) {
+ if (DEBUG) {
+ Slog.d(TAG, "not enable listening visible activity");
+ }
+ return;
+ }
+ mScheduledExecutorService.execute(() -> {
+ if (DEBUG) {
+ Slog.d(TAG, "call updateVisibleActivitiesLocked from activity event");
+ }
+ synchronized (mLock) {
+ updateVisibleActivitiesLocked();
+ }
+ });
+ }
+
+ private List<VisibleActivityInfo> getVisibleActivityInfosLocked() {
+ if (DEBUG) {
+ Slog.d(TAG, "getVisibleActivityInfosLocked");
+ }
+ List<ActivityAssistInfo> allVisibleActivities =
+ LocalServices.getService(ActivityTaskManagerInternal.class)
+ .getTopVisibleActivities();
+ if (DEBUG) {
+ Slog.d(TAG,
+ "getVisibleActivityInfosLocked: allVisibleActivities=" + allVisibleActivities);
+ }
+ if (allVisibleActivities == null || allVisibleActivities.isEmpty()) {
+ Slog.w(TAG, "no visible activity");
+ return null;
+ }
+ final int count = allVisibleActivities.size();
+ final List<VisibleActivityInfo> visibleActivityInfos = new ArrayList<>(count);
+ for (int i = 0; i < count; i++) {
+ ActivityAssistInfo info = allVisibleActivities.get(i);
+ if (DEBUG) {
+ Slog.d(TAG, " : activityToken=" + info.getActivityToken()
+ + ", assistToken=" + info.getAssistToken()
+ + ", taskId=" + info.getTaskId());
+ }
+ visibleActivityInfos.add(
+ new VisibleActivityInfo(info.getTaskId(), info.getAssistToken()));
+ }
+ return visibleActivityInfos;
+ }
+
+ private void updateVisibleActivitiesLocked() {
+ if (DEBUG) {
+ Slog.d(TAG, "updateVisibleActivitiesLocked");
+ }
+ if (mSession == null) {
+ return;
+ }
+ if (!mShown || !mListeningVisibleActivity || mCanceled) {
+ return;
+ }
+ final List<VisibleActivityInfo> newVisibleActivityInfos = getVisibleActivityInfosLocked();
+
+ if (newVisibleActivityInfos == null || newVisibleActivityInfos.isEmpty()) {
+ updateVisibleActivitiesChangedLocked(mVisibleActivityInfos,
+ VisibleActivityInfo.TYPE_ACTIVITY_REMOVED);
+ mVisibleActivityInfos.clear();
+ return;
+ }
+ if (mVisibleActivityInfos.isEmpty()) {
+ updateVisibleActivitiesChangedLocked(newVisibleActivityInfos,
+ VisibleActivityInfo.TYPE_ACTIVITY_ADDED);
+ mVisibleActivityInfos.addAll(newVisibleActivityInfos);
+ return;
+ }
+
+ final List<VisibleActivityInfo> addedActivities = new ArrayList<>();
+ final List<VisibleActivityInfo> removedActivities = new ArrayList<>();
+
+ removedActivities.addAll(mVisibleActivityInfos);
+ for (int i = 0; i < newVisibleActivityInfos.size(); i++) {
+ final VisibleActivityInfo candidateVisibleActivityInfo = newVisibleActivityInfos.get(i);
+ if (!removedActivities.isEmpty() && removedActivities.contains(
+ candidateVisibleActivityInfo)) {
+ removedActivities.remove(candidateVisibleActivityInfo);
+ } else {
+ addedActivities.add(candidateVisibleActivityInfo);
+ }
+ }
+
+ if (!addedActivities.isEmpty()) {
+ updateVisibleActivitiesChangedLocked(addedActivities,
+ VisibleActivityInfo.TYPE_ACTIVITY_ADDED);
+ }
+ if (!removedActivities.isEmpty()) {
+ updateVisibleActivitiesChangedLocked(removedActivities,
+ VisibleActivityInfo.TYPE_ACTIVITY_REMOVED);
+ }
+
+ mVisibleActivityInfos.clear();
+ mVisibleActivityInfos.addAll(newVisibleActivityInfos);
+ }
+
+ private void updateVisibleActivitiesChangedLocked(
+ List<VisibleActivityInfo> visibleActivityInfos, int type) {
+ if (visibleActivityInfos == null || visibleActivityInfos.isEmpty()) {
+ return;
+ }
+ if (mSession == null) {
+ return;
+ }
+ try {
+ for (int i = 0; i < visibleActivityInfos.size(); i++) {
+ mSession.updateVisibleActivityInfo(visibleActivityInfos.get(i), type);
+ }
+ } catch (RemoteException e) {
+ if (DEBUG) {
+ Slog.w(TAG, "updateVisibleActivitiesChangedLocked RemoteException : " + e);
+ }
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "updateVisibleActivitiesChangedLocked type=" + type + ", count="
+ + visibleActivityInfos.size());
+ }
+ }
+
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mLock) {