summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/test-current.txt2
-rw-r--r--core/java/android/app/ActivityManager.java2
-rw-r--r--core/java/android/app/WallpaperManager.java8
-rw-r--r--core/java/android/content/pm/ActivityInfo.java2
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java3
-rw-r--r--core/java/android/widget/RemoteViews.java44
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_split.xml27
-rw-r--r--libs/WindowManager/Shell/res/layout/pip_menu.xml26
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml4
-rw-r--r--libs/WindowManager/Shell/res/values/strings.xml3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java65
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java45
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java19
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java9
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt40
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/config.xml1
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/dimens.xml28
-rw-r--r--packages/SystemUI/res/values/dimens.xml7
-rw-r--r--packages/SystemUI/res/values/styles.xml6
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java50
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/AnimatableClockControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java38
-rw-r--r--services/core/java/com/android/server/am/UserController.java4
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java31
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java17
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java13
-rw-r--r--services/core/java/com/android/server/wm/Task.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java68
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java58
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java28
51 files changed, 667 insertions, 214 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index e3a6dd07b526..a4fb2c1f12ff 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -113,7 +113,7 @@ package android.app {
method @RequiresPermission(android.Manifest.permission.RESET_APP_ERRORS) public void resetAppErrors();
method public static void resumeAppSwitches() throws android.os.RemoteException;
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void setStopUserOnSwitch(int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void setStopUserOnSwitch(int);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean stopUser(int, boolean);
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.DUMP) public void waitForBroadcastIdle();
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f0deecac96c5..992f02ca538b 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4117,7 +4117,7 @@ public class ActivityManager {
*/
@TestApi
@RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
public void setStopUserOnSwitch(@StopUserOnSwitch int value) {
try {
getService().setStopUserOnSwitch(value);
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 11c01e61911c..22b1c03fba50 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -240,6 +240,14 @@ public class WallpaperManager {
*/
public static final String EXTRA_NEW_WALLPAPER_ID = "android.service.wallpaper.extra.ID";
+ /**
+ * Extra passed on {@link Intent.ACTION_WALLPAPER_CHANGED} indicating if wallpaper was set from
+ * a foreground app.
+ * @hide
+ */
+ public static final String EXTRA_FROM_FOREGROUND_APP =
+ "android.service.wallpaper.extra.FROM_FOREGROUND_APP";
+
// flags for which kind of wallpaper to act on
/** @hide */
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index c0cb44286479..b5298fc9e1c7 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1015,7 +1015,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
*/
@ChangeId
@Overridable
- @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S_V2)
@TestApi
public static final long OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY = 203647190L; // buganizer id
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 2d263a54b874..c77399f692f0 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1575,7 +1575,7 @@ public abstract class WallpaperService extends Service {
void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages,
float xOffsetStep) {
// to save creating a runnable, check twice
- long current = SystemClock.elapsedRealtime();
+ long current = System.currentTimeMillis();
long lapsed = current - currentPage.getLastUpdateTime();
// Always update the page when the last update time is <= 0
// This is important especially when the device first boots
@@ -1768,6 +1768,7 @@ public abstract class WallpaperService extends Service {
return;
}
}
+ processLocalColors(mPendingXOffset, mPendingYOffset);
}
/**
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 2357d13c8d41..f724285df9dc 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -5735,24 +5735,44 @@ public class RemoteViews implements Parcelable, Filter {
return previousLayoutId == getLayoutId() && mViewId == overrideId;
}
- // Note: topLevel should be true only for calls on the topLevel RemoteViews, internal calls
- // should set it to false.
- private void reapply(Context context, View v, InteractionHandler handler, SizeF size,
- ColorResources colorResources, boolean topLevel) {
-
+ /**
+ * Returns the RemoteViews that should be used in the reapply operation.
+ *
+ * If the current RemoteViews has multiple layout, this will select the correct one.
+ *
+ * @throws RuntimeException If the current RemoteViews should not be reapplied onto the provided
+ * View.
+ */
+ private RemoteViews getRemoteViewsToReapply(Context context, View v, @Nullable SizeF size) {
RemoteViews rvToApply = getRemoteViewsToApply(context, size);
// In the case that a view has this RemoteViews applied in one orientation or size, is
// persisted across change, and has the RemoteViews re-applied in a different situation
// (orientation or size), we throw an exception, since the layouts may be completely
// unrelated.
- if (hasMultipleLayouts()) {
+ // If the ViewID has been changed on the view, or is changed by the RemoteViews, we also
+ // may throw an exception, as the RemoteViews will probably not apply properly.
+ // However, we need to let potentially unrelated RemoteViews apply, as this lack of testing
+ // is already used in production code in some apps.
+ if (hasMultipleLayouts()
+ || rvToApply.mViewId != View.NO_ID
+ || v.getTag(R.id.remote_views_override_id) != null) {
if (!rvToApply.canRecycleView(v)) {
throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" +
" that does not share the same root layout id.");
}
}
+ return rvToApply;
+ }
+
+ // Note: topLevel should be true only for calls on the topLevel RemoteViews, internal calls
+ // should set it to false.
+ private void reapply(Context context, View v, InteractionHandler handler, SizeF size,
+ ColorResources colorResources, boolean topLevel) {
+
+ RemoteViews rvToApply = getRemoteViewsToReapply(context, v, size);
+
rvToApply.performApply(v, (ViewGroup) v.getParent(), handler, colorResources);
// If the parent of the view is has is a root, resolve the recycling.
@@ -5789,17 +5809,7 @@ public class RemoteViews implements Parcelable, Filter {
public CancellationSignal reapplyAsync(Context context, View v, Executor executor,
OnViewAppliedListener listener, InteractionHandler handler, SizeF size,
ColorResources colorResources) {
- RemoteViews rvToApply = getRemoteViewsToApply(context, size);
-
- // In the case that a view has this RemoteViews applied in one orientation, is persisted
- // across orientation change, and has the RemoteViews re-applied in the new orientation,
- // we throw an exception, since the layouts may be completely unrelated.
- if (hasMultipleLayouts()) {
- if (!rvToApply.canRecycleView(v)) {
- throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" +
- " that does not share the same root layout id.");
- }
- }
+ RemoteViews rvToApply = getRemoteViewsToReapply(context, v, size);
return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
context, listener, handler, colorResources, v, true /* topLevel */)
diff --git a/libs/WindowManager/Shell/res/drawable/pip_split.xml b/libs/WindowManager/Shell/res/drawable/pip_split.xml
new file mode 100644
index 000000000000..2cfdf6ed259b
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/pip_split.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/pip_expand_action_inner_size"
+ android:height="@dimen/pip_expand_action_inner_size"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M20,18h-5V6h5V18z M22,18V6c0-1.1-0.9-2-2-2h-5c-1.1,0-2,0.9-2,2v12c0,1.1,0.9,2,2,2h5C21.1,20,22,19.1,22,18z M9,18H4V6h5
+ V18z M11,18V6c0-1.1-0.9-2-2-2H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h5C10.1,20,11,19.1,11,18z" />
+</vector>
diff --git a/libs/WindowManager/Shell/res/layout/pip_menu.xml b/libs/WindowManager/Shell/res/layout/pip_menu.xml
index 9fe024748610..1dd17bad155b 100644
--- a/libs/WindowManager/Shell/res/layout/pip_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/pip_menu.xml
@@ -65,25 +65,29 @@
<LinearLayout
android:id="@+id/top_end_container"
android:layout_gravity="top|end"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
+
<ImageButton
android:id="@+id/settings"
android:layout_width="@dimen/pip_action_size"
android:layout_height="@dimen/pip_action_size"
android:contentDescription="@string/pip_phone_settings"
+ android:layout_gravity="top|start"
android:gravity="center"
android:src="@drawable/pip_ic_settings"
android:background="?android:selectableItemBackgroundBorderless" />
<ImageButton
- android:id="@+id/dismiss"
- android:layout_width="@dimen/pip_action_size"
- android:layout_height="@dimen/pip_action_size"
- android:contentDescription="@string/pip_phone_close"
+ android:id="@+id/enter_split"
+ android:layout_width="@dimen/pip_split_icon_size"
+ android:layout_height="@dimen/pip_split_icon_size"
+ android:layout_gravity="top|start"
+ android:layout_margin="@dimen/pip_split_icon_margin"
android:gravity="center"
- android:src="@drawable/pip_ic_close_white"
+ android:contentDescription="@string/pip_phone_enter_split"
+ android:src="@drawable/pip_split"
android:background="?android:selectableItemBackgroundBorderless" />
</LinearLayout>
@@ -97,4 +101,14 @@
android:padding="@dimen/pip_resize_handle_padding"
android:src="@drawable/pip_resize_handle"
android:background="?android:selectableItemBackgroundBorderless" />
+
+ <ImageButton
+ android:id="@+id/dismiss"
+ android:layout_width="@dimen/pip_action_size"
+ android:layout_height="@dimen/pip_action_size"
+ android:contentDescription="@string/pip_phone_close"
+ android:layout_gravity="top|end"
+ android:gravity="center"
+ android:src="@drawable/pip_ic_close_white"
+ android:background="?android:selectableItemBackgroundBorderless" />
</FrameLayout>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index e9b9ec3f7d89..9e77578eafd8 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -67,6 +67,10 @@
<dimen name="pip_resize_handle_margin">4dp</dimen>
<dimen name="pip_resize_handle_padding">0dp</dimen>
+ <!-- PIP Split icon size and margin. -->
+ <dimen name="pip_split_icon_size">24dp</dimen>
+ <dimen name="pip_split_icon_margin">12dp</dimen>
+
<!-- PIP stash offset size, which is the width of visible PIP region when stashed. -->
<dimen name="pip_stash_offset">32dp</dimen>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 764854af3b3f..c88fc16e218e 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -24,6 +24,9 @@
<!-- Label for PIP settings button [CHAR LIMIT=NONE]-->
<string name="pip_phone_settings">Settings</string>
+ <!-- Label for the PIP enter split button [CHAR LIMIT=NONE] -->
+ <string name="pip_phone_enter_split">Enter split screen</string>
+
<!-- Title of menu shown over picture-in-picture. Used for accessibility. -->
<string name="pip_menu_title">Menu</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
index b80dcd063589..711a0ac76702 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
@@ -43,6 +43,7 @@ import com.android.wm.shell.pip.tv.TvPipController;
import com.android.wm.shell.pip.tv.TvPipMenuController;
import com.android.wm.shell.pip.tv.TvPipNotificationController;
import com.android.wm.shell.pip.tv.TvPipTransition;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
@@ -160,13 +161,14 @@ public abstract class TvPipModule {
PipTransitionController pipTransitionController,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
Optional<LegacySplitScreenController> splitScreenOptional,
+ Optional<SplitScreenController> newSplitScreenOptional,
DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
@ShellMainThread ShellExecutor mainExecutor) {
return new PipTaskOrganizer(context,
syncTransactionQueue, pipTransitionState, pipBoundsState, pipBoundsAlgorithm,
tvPipMenuController, pipAnimationController, pipSurfaceTransactionHelper,
- pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger,
- shellTaskOrganizer, mainExecutor);
+ pipTransitionController, splitScreenOptional, newSplitScreenOptional,
+ displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 944dfed57cb6..ec701470354c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -55,6 +55,7 @@ import com.android.wm.shell.pip.phone.PipAppOpsListener;
import com.android.wm.shell.pip.phone.PipController;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.pip.phone.PipTouchHandler;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm;
import com.android.wm.shell.startingsurface.phone.PhoneStartingWindowTypeAlgorithm;
import com.android.wm.shell.transition.Transitions;
@@ -215,14 +216,15 @@ public class WMShellModule {
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
PipTransitionController pipTransitionController,
Optional<LegacySplitScreenController> splitScreenOptional,
+ Optional<SplitScreenController> newSplitScreenOptional,
DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
@ShellMainThread ShellExecutor mainExecutor) {
return new PipTaskOrganizer(context,
syncTransactionQueue, pipTransitionState, pipBoundsState, pipBoundsAlgorithm,
menuPhoneController, pipAnimationController, pipSurfaceTransactionHelper,
- pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger,
- shellTaskOrganizer, mainExecutor);
+ pipTransitionController, splitScreenOptional, newSplitScreenOptional,
+ displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index b6e5804a64dd..6cc5f09827af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -77,6 +77,7 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.phone.PipMotionHelper;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
@@ -126,7 +127,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private final int mExitAnimationDuration;
private final int mCrossFadeAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
- private final Optional<LegacySplitScreenController> mSplitScreenOptional;
+ private final Optional<LegacySplitScreenController> mLegacySplitScreenOptional;
+ private final Optional<SplitScreenController> mSplitScreenOptional;
protected final ShellTaskOrganizer mTaskOrganizer;
protected final ShellExecutor mMainExecutor;
@@ -252,7 +254,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
@NonNull PipAnimationController pipAnimationController,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
@NonNull PipTransitionController pipTransitionController,
- Optional<LegacySplitScreenController> splitScreenOptional,
+ Optional<LegacySplitScreenController> legacySplitScreenOptional,
+ Optional<SplitScreenController> splitScreenOptional,
@NonNull DisplayController displayController,
@NonNull PipUiEventLogger pipUiEventLogger,
@NonNull ShellTaskOrganizer shellTaskOrganizer,
@@ -274,6 +277,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mPipAnimationController = pipAnimationController;
mPipUiEventLoggerLogger = pipUiEventLogger;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
+ mLegacySplitScreenOptional = legacySplitScreenOptional;
mSplitScreenOptional = splitScreenOptional;
mTaskOrganizer = shellTaskOrganizer;
mMainExecutor = mainExecutor;
@@ -373,8 +377,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
* activity render it's final configuration while the Task is still in PiP.
* - setWindowingMode to undefined at the end of transition
* @param animationDurationMs duration in millisecond for the exiting PiP transition
+ * @param requestEnterSplit whether the enterSplit button is pressed on PiP or not.
+ * Indicate the user wishes to directly put PiP into split screen
+ * mode.
*/
- public void exitPip(int animationDurationMs) {
+ public void exitPip(int animationDurationMs, boolean requestEnterSplit) {
if (!mPipTransitionState.isInPip()
|| mPipTransitionState.getTransitionState() == PipTransitionState.EXITING_PIP
|| mToken == null) {
@@ -387,7 +394,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
final WindowContainerTransaction wct = new WindowContainerTransaction();
final Rect destinationBounds = mPipBoundsState.getDisplayBounds();
- final int direction = syncWithSplitScreenBounds(destinationBounds)
+ final int direction = syncWithSplitScreenBounds(destinationBounds, requestEnterSplit)
? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
: TRANSITION_DIRECTION_LEAVE_PIP;
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
@@ -396,7 +403,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
// We set to fullscreen here for now, but later it will be set to UNDEFINED for
// the proper windowing mode to take place. See #applyWindowingModeChangeOnExit.
wct.setActivityWindowingMode(mToken,
- direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
+ direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN && !requestEnterSplit
? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
: WINDOWING_MODE_FULLSCREEN);
wct.setBounds(mToken, destinationBounds);
@@ -435,7 +442,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
wct.setWindowingMode(mToken, getOutPipWindowingMode());
// Simply reset the activity mode set prior to the animation running.
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
- mSplitScreenOptional.ifPresent(splitScreen -> {
+ mLegacySplitScreenOptional.ifPresent(splitScreen -> {
if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
wct.reparent(mToken, splitScreen.getSecondaryRoot(), true /* onTop */);
}
@@ -1165,6 +1172,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
@PipAnimationController.TransitionDirection int direction,
@PipAnimationController.AnimationType int type) {
final Rect preResizeBounds = new Rect(mPipBoundsState.getBounds());
+ final boolean isPipTopLeft = isPipTopLeft();
mPipBoundsState.setBounds(destinationBounds);
if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
removePipImmediately();
@@ -1210,10 +1218,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
null /* callback */, false /* withStartDelay */);
});
} else {
- applyFinishBoundsResize(wct, direction);
+ applyFinishBoundsResize(wct, direction, isPipTopLeft);
}
} else {
- applyFinishBoundsResize(wct, direction);
+ applyFinishBoundsResize(wct, direction, isPipTopLeft);
}
finishResizeForMenu(destinationBounds);
@@ -1241,7 +1249,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
} else if (isOutPipDirection(direction)) {
// If we are animating to fullscreen or split screen, then we need to reset the
// override bounds on the task to ensure that the task "matches" the parent's bounds.
- taskBounds = null;
+ if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
+ taskBounds = destinationBounds;
+ } else {
+ taskBounds = null;
+ }
applyWindowingModeChangeOnExit(wct, direction);
} else {
// Just a resize in PIP
@@ -1261,8 +1273,20 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
* applying it.
*/
public void applyFinishBoundsResize(@NonNull WindowContainerTransaction wct,
- @PipAnimationController.TransitionDirection int direction) {
- mTaskOrganizer.applyTransaction(wct);
+ @PipAnimationController.TransitionDirection int direction, boolean wasPipTopLeft) {
+ if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
+ mSplitScreenOptional.get().enterSplitScreen(mTaskInfo.taskId, wasPipTopLeft, wct);
+ } else {
+ mTaskOrganizer.applyTransaction(wct);
+ }
+ }
+
+ private boolean isPipTopLeft() {
+ final Rect topLeft = new Rect();
+ final Rect bottomRight = new Rect();
+ mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
+
+ return topLeft.contains(mPipBoundsState.getBounds());
}
/**
@@ -1347,18 +1371,27 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
/**
- * Sync with {@link LegacySplitScreenController} on destination bounds if PiP is going to split
- * screen.
+ * Sync with {@link LegacySplitScreenController} or {@link SplitScreenController} on destination
+ * bounds if PiP is going to split screen.
*
* @param destinationBoundsOut contain the updated destination bounds if applicable
* @return {@code true} if destinationBounds is altered for split screen
*/
- private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut) {
- if (!mSplitScreenOptional.isPresent()) {
+ private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut, boolean enterSplit) {
+ if (enterSplit && mSplitScreenOptional.isPresent()) {
+ final Rect topLeft = new Rect();
+ final Rect bottomRight = new Rect();
+ mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
+ final boolean isPipTopLeft = isPipTopLeft();
+ destinationBoundsOut.set(isPipTopLeft ? topLeft : bottomRight);
+ return true;
+ }
+
+ if (!mLegacySplitScreenOptional.isPresent()) {
return false;
}
- LegacySplitScreenController legacySplitScreen = mSplitScreenOptional.get();
+ LegacySplitScreenController legacySplitScreen = mLegacySplitScreenOptional.get();
if (!legacySplitScreen.isDividerVisible()) {
// fail early if system is not in split screen mode
return false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index ae8c1b6f8c1a..5687f4d62444 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -95,6 +95,11 @@ public class PhonePipMenuController implements PipMenuController {
* Called when the PIP requested to show the menu.
*/
void onPipShowMenu();
+
+ /**
+ * Called when the PIP requested to enter Split.
+ */
+ void onEnterSplit();
}
private final Matrix mMoveTransform = new Matrix();
@@ -458,6 +463,10 @@ public class PhonePipMenuController implements PipMenuController {
mListeners.forEach(Listener::onPipDismiss);
}
+ void onEnterSplit() {
+ mListeners.forEach(Listener::onEnterSplit);
+ }
+
/**
* @return the best set of actions to show in the PiP menu.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
index 47a8c67a22e6..69ae45d12795 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
@@ -151,7 +151,7 @@ public class PipAccessibilityInteractionConnection {
result = true;
break;
case AccessibilityNodeInfo.ACTION_EXPAND:
- mMotionHelper.expandLeavePip();
+ mMotionHelper.expandLeavePip(false /* skipAnimation */);
result = true;
break;
default:
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 8c431f08a385..10bc7e250cc8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -482,7 +482,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
false /* fromShelfAdjustment */,
wct /* windowContainerTransaction */);
if (wct != null) {
- mPipTaskOrganizer.applyFinishBoundsResize(wct, TRANSITION_DIRECTION_SAME);
+ mPipTaskOrganizer.applyFinishBoundsResize(wct, TRANSITION_DIRECTION_SAME,
+ false /* wasPipTopLeft */);
}
};
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
index 3eeba6eb5366..06446573840c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
@@ -18,8 +18,6 @@ package com.android.wm.shell.pip.phone;
import android.content.Context;
import android.graphics.Rect;
-import android.util.Log;
-import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -34,6 +32,7 @@ public class PipMenuIconsAlgorithm {
protected ViewGroup mViewRoot;
protected ViewGroup mTopEndContainer;
protected View mDragHandle;
+ protected View mEnterSplitButton;
protected View mSettingsButton;
protected View mDismissButton;
@@ -44,14 +43,13 @@ public class PipMenuIconsAlgorithm {
* Bind the necessary views.
*/
public void bindViews(ViewGroup viewRoot, ViewGroup topEndContainer, View dragHandle,
- View settingsButton, View dismissButton) {
+ View enterSplitButton, View settingsButton, View dismissButton) {
mViewRoot = viewRoot;
mTopEndContainer = topEndContainer;
mDragHandle = dragHandle;
+ mEnterSplitButton = enterSplitButton;
mSettingsButton = settingsButton;
mDismissButton = dismissButton;
-
- bindInitialViewState();
}
/**
@@ -72,22 +70,4 @@ public class PipMenuIconsAlgorithm {
v.setLayoutParams(params);
}
}
-
- /** Calculate the initial state of the menu icons. Called when the menu is first created. */
- private void bindInitialViewState() {
- if (mViewRoot == null || mTopEndContainer == null || mDragHandle == null
- || mSettingsButton == null || mDismissButton == null) {
- Log.e(TAG, "One of the required views is null.");
- return;
- }
- // The menu view layout starts out with the settings button aligned at the top|end of the
- // view group next to the dismiss button. On phones, the settings button should be aligned
- // to the top|start of the view, so move it to parent view group to then align it to the
- // top|start of the menu.
- mTopEndContainer.removeView(mSettingsButton);
- mViewRoot.addView(mSettingsButton);
-
- setLayoutGravity(mDragHandle, Gravity.START | Gravity.TOP);
- setLayoutGravity(mSettingsButton, Gravity.START | Gravity.TOP);
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 8ef2b6b12030..b209699c1a19 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -99,7 +99,7 @@ public class PipMenuView extends FrameLayout {
private static final float MENU_BACKGROUND_ALPHA = 0.3f;
private static final float DISABLED_ACTION_ALPHA = 0.54f;
- private static final boolean ENABLE_RESIZE_HANDLE = false;
+ private static final boolean ENABLE_ENTER_SPLIT = true;
private int mMenuState;
private boolean mAllowMenuTimeout = true;
@@ -139,7 +139,7 @@ public class PipMenuView extends FrameLayout {
protected View mViewRoot;
protected View mSettingsButton;
protected View mDismissButton;
- protected View mResizeHandle;
+ protected View mEnterSplitButton;
protected View mTopEndContainer;
protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
@@ -177,14 +177,23 @@ public class PipMenuView extends FrameLayout {
}
});
- mResizeHandle = findViewById(R.id.resize_handle);
- mResizeHandle.setAlpha(0);
+ mEnterSplitButton = findViewById(R.id.enter_split);
+ mEnterSplitButton.setAlpha(0);
+ mEnterSplitButton.setOnClickListener(v -> {
+ if (mMenuContainer.getAlpha() != 0) {
+ enterSplit();
+ }
+ });
+
+ findViewById(R.id.resize_handle).setAlpha(0);
+
mActionsGroup = findViewById(R.id.actions_group);
mBetweenActionPaddingLand = getResources().getDimensionPixelSize(
R.dimen.pip_between_action_padding_land);
mPipMenuIconsAlgorithm = new PipMenuIconsAlgorithm(mContext);
mPipMenuIconsAlgorithm.bindViews((ViewGroup) mViewRoot, (ViewGroup) mTopEndContainer,
- mResizeHandle, mSettingsButton, mDismissButton);
+ findViewById(R.id.resize_handle), mEnterSplitButton, mSettingsButton,
+ mDismissButton);
mDismissFadeOutDurationMs = context.getResources()
.getInteger(R.integer.config_pipExitAnimationDuration);
@@ -268,14 +277,13 @@ public class PipMenuView extends FrameLayout {
mSettingsButton.getAlpha(), 1f);
ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
mDismissButton.getAlpha(), 1f);
- ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
- mResizeHandle.getAlpha(),
- ENABLE_RESIZE_HANDLE && showResizeHandle ? 1f : 0f);
+ ObjectAnimator enterSplitAnim = ObjectAnimator.ofFloat(mEnterSplitButton, View.ALPHA,
+ mEnterSplitButton.getAlpha(), ENABLE_ENTER_SPLIT ? 1f : 0f);
if (menuState == MENU_STATE_FULL) {
mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
- resizeAnim);
+ enterSplitAnim);
} else {
- mMenuContainerAnimator.playTogether(resizeAnim);
+ mMenuContainerAnimator.playTogether(enterSplitAnim);
}
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
mMenuContainerAnimator.setDuration(ANIMATION_HIDE_DURATION_MS);
@@ -328,7 +336,7 @@ public class PipMenuView extends FrameLayout {
mMenuContainer.setAlpha(0f);
mSettingsButton.setAlpha(0f);
mDismissButton.setAlpha(0f);
- mResizeHandle.setAlpha(0f);
+ mEnterSplitButton.setAlpha(0f);
}
void pokeMenu() {
@@ -368,9 +376,10 @@ public class PipMenuView extends FrameLayout {
mSettingsButton.getAlpha(), 0f);
ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
mDismissButton.getAlpha(), 0f);
- ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
- mResizeHandle.getAlpha(), 0f);
- mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim, resizeAnim);
+ ObjectAnimator enterSplitAnim = ObjectAnimator.ofFloat(mEnterSplitButton, View.ALPHA,
+ mEnterSplitButton.getAlpha(), 0f);
+ mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
+ enterSplitAnim);
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT);
mMenuContainerAnimator.setDuration(getFadeOutDuration(animationType));
mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
@@ -522,6 +531,14 @@ public class PipMenuView extends FrameLayout {
}
}
+ private void enterSplit() {
+ // Do not notify menu visibility when hiding the menu, the controller will do this when it
+ // handles the message
+ hideMenu(mController::onEnterSplit, false /* notifyMenuVisibility */, true /* resize */,
+ ANIM_TYPE_HIDE);
+ }
+
+
private void showSettings() {
final Pair<ComponentName, Integer> topPipActivityInfo =
PipUtils.getTopPipActivity(mContext);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index dbd09fd7b265..c634b7f220b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -338,22 +338,29 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
* Resizes the pinned stack back to unknown windowing mode, which could be freeform or
* * fullscreen depending on the display area's windowing mode.
*/
- void expandLeavePip() {
- expandLeavePip(false /* skipAnimation */);
+ void expandLeavePip(boolean skipAnimation) {
+ expandLeavePip(skipAnimation, false /* enterSplit */);
+ }
+
+ /**
+ * Resizes the pinned task to split-screen mode.
+ */
+ void expandIntoSplit() {
+ expandLeavePip(false, true /* enterSplit */);
}
/**
* Resizes the pinned stack back to unknown windowing mode, which could be freeform or
* fullscreen depending on the display area's windowing mode.
*/
- void expandLeavePip(boolean skipAnimation) {
+ private void expandLeavePip(boolean skipAnimation, boolean enterSplit) {
if (DEBUG) {
Log.d(TAG, "exitPip: skipAnimation=" + skipAnimation
+ " callers=\n" + Debug.getCallers(5, " "));
}
cancelPhysicsAnimation();
mMenuController.hideMenu(ANIM_TYPE_NONE, false /* resize */);
- mPipTaskOrganizer.exitPip(skipAnimation ? 0 : LEAVE_PIP_DURATION);
+ mPipTaskOrganizer.exitPip(skipAnimation ? 0 : LEAVE_PIP_DURATION, enterSplit);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 9f2f6a575aca..570fd5eab9f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -139,7 +139,12 @@ public class PipTouchHandler {
@Override
public void onPipExpand() {
- mMotionHelper.expandLeavePip();
+ mMotionHelper.expandLeavePip(false /* skipAnimation */);
+ }
+
+ @Override
+ public void onEnterSplit() {
+ mMotionHelper.expandIntoSplit();
}
@Override
@@ -899,7 +904,7 @@ public class PipTouchHandler {
// Expand to fullscreen if this is a double tap
// the PiP should be frozen until the transition ends
setTouchEnabled(false);
- mMotionHelper.expandLeavePip();
+ mMotionHelper.expandLeavePip(false /* skipAnimation */);
}
} else if (mMenuState != MENU_STATE_FULL) {
if (mPipBoundsState.isStashed()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index a2e9b64046fd..00083d986dbe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -219,7 +219,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
public void movePipToFullscreen() {
if (DEBUG) Log.d(TAG, "movePipToFullscreen(), state=" + stateToName(mState));
- mPipTaskOrganizer.exitPip(mResizeAnimationDuration);
+ mPipTaskOrganizer.exitPip(mResizeAnimationDuration, false /* requestEnterSplit */);
onPipDisappeared();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 04058ed6388c..7457be2d0871 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -202,11 +202,25 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
return moveToSideStage(task, sideStagePosition);
}
+ public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition,
+ WindowContainerTransaction wct) {
+ final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
+ if (task == null) {
+ throw new IllegalArgumentException("Unknown taskId" + taskId);
+ }
+ return moveToSideStage(task, sideStagePosition, wct);
+ }
+
public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
@SplitPosition int sideStagePosition) {
return mStageCoordinator.moveToSideStage(task, sideStagePosition);
}
+ public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
+ @SplitPosition int sideStagePosition, WindowContainerTransaction wct) {
+ return mStageCoordinator.moveToSideStage(task, sideStagePosition, wct);
+ }
+
public boolean removeFromSideStage(int taskId) {
return mStageCoordinator.removeFromSideStage(taskId);
}
@@ -224,6 +238,11 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
}
+ public void enterSplitScreen(int taskId, boolean leftOrTop, WindowContainerTransaction wct) {
+ moveToSideStage(taskId,
+ leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+ }
+
public void exitSplitScreen(int toTopTaskId, @ExitReason int exitReason) {
mStageCoordinator.exitSplitScreen(toTopTaskId, exitReason);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 3589f7c14cd3..95886c8f3deb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -281,6 +281,11 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
@SplitPosition int sideStagePosition) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
+ return moveToSideStage(task, sideStagePosition, wct);
+ }
+
+ boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
+ @SplitPosition int sideStagePosition, WindowContainerTransaction wct) {
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
setSideStagePosition(sideStagePosition, wct);
mSideStage.evictAllChildren(evictWct);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 0270093da938..0172cf324eea 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -50,6 +50,7 @@ import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import org.junit.Before;
import org.junit.Test;
@@ -75,7 +76,8 @@ public class PipTaskOrganizerTest extends ShellTestCase {
@Mock private PipTransitionController mMockPipTransitionController;
@Mock private PipSurfaceTransactionHelper mMockPipSurfaceTransactionHelper;
@Mock private PipUiEventLogger mMockPipUiEventLogger;
- @Mock private Optional<LegacySplitScreenController> mMockOptionalSplitScreen;
+ @Mock private Optional<LegacySplitScreenController> mMockOptionalLegacySplitScreen;
+ @Mock private Optional<SplitScreenController> mMockOptionalSplitScreen;
@Mock private ShellTaskOrganizer mMockShellTaskOrganizer;
private TestShellExecutor mMainExecutor;
private PipBoundsState mPipBoundsState;
@@ -99,8 +101,9 @@ public class PipTaskOrganizerTest extends ShellTestCase {
mMockSyncTransactionQueue, mPipTransitionState, mPipBoundsState,
mPipBoundsAlgorithm, mMockPhonePipMenuController,
mMockPipAnimationController, mMockPipSurfaceTransactionHelper,
- mMockPipTransitionController, mMockOptionalSplitScreen, mMockDisplayController,
- mMockPipUiEventLogger, mMockShellTaskOrganizer, mMainExecutor));
+ mMockPipTransitionController, mMockOptionalLegacySplitScreen,
+ mMockOptionalSplitScreen, mMockDisplayController, mMockPipUiEventLogger,
+ mMockShellTaskOrganizer, mMainExecutor));
mMainExecutor.flushAll();
preparePipTaskOrg();
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index faa7554525c5..413612ff9a76 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -54,8 +54,12 @@ class DialogLaunchAnimator(
private val TAG_LAUNCH_ANIMATION_RUNNING = R.id.launch_animation_running
}
+ /**
+ * The set of dialogs that were animated using this animator and that are still opened (not
+ * dismissed, but can be hidden).
+ */
// TODO(b/201264644): Remove this set.
- private val currentAnimations = hashSetOf<DialogLaunchAnimation>()
+ private val openedDialogs = hashSetOf<AnimatedDialog>()
/**
* Show [dialog] by expanding it from [view]. If [animateBackgroundBoundsChange] is true, then
@@ -79,21 +83,29 @@ class DialogLaunchAnimator(
"the main thread")
}
+ // If the parent of the view we are launching from is the background of some other animated
+ // dialog, then this means the caller intent is to launch a dialog from another dialog. In
+ // this case, we also animate the parent (which is the dialog background).
+ val dialogContentParent = openedDialogs
+ .firstOrNull { it.dialogContentParent == view.parent }
+ ?.dialogContentParent
+ val animateFrom = dialogContentParent ?: view
+
// 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) {
+ if (animateFrom.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)
+ animateFrom.setTag(TAG_LAUNCH_ANIMATION_RUNNING, true)
- val launchAnimation = DialogLaunchAnimation(
- context, launchAnimator, hostDialogProvider, view,
- onDialogDismissed = { currentAnimations.remove(it) }, originalDialog = dialog,
+ val launchAnimation = AnimatedDialog(
+ context, launchAnimator, hostDialogProvider, animateFrom,
+ onDialogDismissed = { openedDialogs.remove(it) }, originalDialog = dialog,
animateBackgroundBoundsChange)
val hostDialog = launchAnimation.hostDialog
- currentAnimations.add(launchAnimation)
+ openedDialogs.add(launchAnimation)
// If the dialog is dismissed/hidden/shown, then we should actually dismiss/hide/show the
// host dialog.
@@ -151,7 +163,7 @@ class DialogLaunchAnimator(
* TODO(b/193634619): Remove this function and animate dialog into opening activity instead.
*/
fun disableAllCurrentDialogsExitAnimations() {
- currentAnimations.forEach { it.exitAnimationDisabled = true }
+ openedDialogs.forEach { it.exitAnimationDisabled = true }
}
}
@@ -206,7 +218,7 @@ interface DialogListener {
fun onSizeChanged()
}
-private class DialogLaunchAnimation(
+private class AnimatedDialog(
private val context: Context,
private val launchAnimator: LaunchAnimator,
hostDialogProvider: HostDialogProvider,
@@ -215,10 +227,10 @@ private class DialogLaunchAnimation(
private val touchSurface: View,
/**
- * A callback that will be called with this [DialogLaunchAnimation] after the dialog was
+ * A callback that will be called with this [AnimatedDialog] after the dialog was
* dismissed and the exit animation is done.
*/
- private val onDialogDismissed: (DialogLaunchAnimation) -> Unit,
+ private val onDialogDismissed: (AnimatedDialog) -> Unit,
/** The original dialog whose content will be shown and animate in/out in [hostDialog]. */
private val originalDialog: Dialog,
@@ -241,7 +253,7 @@ private class DialogLaunchAnimation(
* the same size as the original dialog window and to which we will set the original dialog
* window background.
*/
- private val dialogContentParent = FrameLayout(context)
+ val dialogContentParent = FrameLayout(context)
/**
* The background color of [originalDialogView], taking into consideration the [originalDialog]
@@ -574,7 +586,7 @@ private class DialogLaunchAnimation(
}
dismissDialogs(false /* instantDismiss */)
- onDialogDismissed(this@DialogLaunchAnimation)
+ onDialogDismissed(this@AnimatedDialog)
return
}
@@ -610,7 +622,7 @@ private class DialogLaunchAnimation(
// and instantly dismiss the dialog.
GhostView.removeGhost(touchSurface)
dismissDialogs(true /* instantDismiss */)
- onDialogDismissed(this@DialogLaunchAnimation)
+ onDialogDismissed(this@AnimatedDialog)
return true
}
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index 040df865bfe5..362e18d785ac 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -33,5 +33,4 @@
<!-- Notifications are sized to match the width of two (of 4) qs tiles in landscape. -->
<bool name="config_skinnyNotifsInLandscape">false</bool>
- <dimen name="keyguard_indication_margin_bottom">25dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
new file mode 100644
index 000000000000..3cfe05638032
--- /dev/null
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -0,0 +1,28 @@
+<?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>
+
+ <!-- keyguard-->
+ <dimen name="keyguard_indication_margin_bottom">25dp</dimen>
+ <dimen name="ambient_indication_margin_bottom">115dp</dimen>
+ <dimen name="lock_icon_margin_bottom">60dp</dimen>
+
+ <!-- margin from keyguard status bar to clock. For split shade it should be
+ keyguard_split_shade_top_margin - status_bar_header_height_keyguard = 8dp -->
+ <dimen name="keyguard_clock_top_margin">8dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 44589dee1126..6875cab8a7b2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -753,6 +753,9 @@
<!-- Minimum distance the user has to drag down to go to the full shade. -->
<dimen name="keyguard_drag_down_min_distance">100dp</dimen>
+ <!-- The margin from the top of the screen to notifications and keyguard status view in
+ split shade on keyguard-->
+ <dimen name="keyguard_split_shade_top_margin">68dp</dimen>
<!-- The margin between the status view and the notifications on Keyguard.-->
<dimen name="keyguard_status_view_bottom_margin">20dp</dimen>
<!-- Minimum margin between clock and status bar -->
@@ -935,7 +938,9 @@
<dimen name="keyguard_lock_padding">20dp</dimen>
<dimen name="keyguard_indication_margin_bottom">32dp</dimen>
- <dimen name="lock_icon_margin_bottom">98dp</dimen>
+ <dimen name="lock_icon_margin_bottom">110dp</dimen>
+ <dimen name="ambient_indication_margin_bottom">71dp</dimen>
+
<!-- The text size for battery level -->
<dimen name="battery_level_text_size">12sp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 4d2986f40a33..7216ac6e5702 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -266,8 +266,6 @@
<item name="android:paddingTop">12dp</item>
<item name="android:paddingHorizontal">24dp</item>
<item name="android:textSize">24sp</item>
- <item name="android:singleLine">true</item>
- <item name="android:ellipsize">marquee</item>
</style>
<style name="TextAppearance.AuthCredential.Subtitle">
@@ -275,8 +273,6 @@
<item name="android:paddingTop">8dp</item>
<item name="android:paddingHorizontal">24dp</item>
<item name="android:textSize">16sp</item>
- <item name="android:singleLine">true</item>
- <item name="android:ellipsize">marquee</item>
</style>
<style name="TextAppearance.AuthCredential.Description">
@@ -284,8 +280,6 @@
<item name="android:paddingTop">8dp</item>
<item name="android:paddingHorizontal">24dp</item>
<item name="android:textSize">14sp</item>
- <item name="android:singleLine">true</item>
- <item name="android:ellipsize">marquee</item>
</style>
<style name="TextAppearance.AuthCredential.Error">
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index 3f2ff742d072..3128ffdbc67b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -23,17 +23,14 @@ import android.app.ActivityManager.TaskDescription;
import android.app.TaskInfo;
import android.content.ComponentName;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.ViewDebug;
-import com.android.systemui.shared.recents.utilities.Utilities;
+import androidx.annotation.Nullable;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.Objects;
/**
@@ -202,8 +199,8 @@ public class Task {
* The icon is the task description icon (if provided), which falls back to the activity icon,
* which can then fall back to the application icon.
*/
- public Drawable icon;
- public ThumbnailData thumbnail;
+ @Nullable public Drawable icon;
+ @Nullable public ThumbnailData thumbnail;
@ViewDebug.ExportedProperty(category="recents")
@Deprecated
public String title;
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
index a383cab94c36..ac463ebc1c97 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
@@ -31,7 +31,6 @@ import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.ViewController;
@@ -49,7 +48,6 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie
private final StatusBarStateController mStatusBarStateController;
private final BroadcastDispatcher mBroadcastDispatcher;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final KeyguardBypassController mBypassController;
private final BatteryController mBatteryController;
private final int mDozingColor = Color.WHITE;
private int mLockScreenColor;
@@ -71,14 +69,12 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie
BroadcastDispatcher broadcastDispatcher,
BatteryController batteryController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- KeyguardBypassController bypassController,
@Main Resources resources
) {
super(view);
mStatusBarStateController = statusBarStateController;
mBroadcastDispatcher = broadcastDispatcher;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mBypassController = bypassController;
mBatteryController = batteryController;
mBurmeseNumerals = mBurmeseNf.format(FORMAT_NUMBER);
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
index ef3104a21708..2a0c2855c3b2 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
@@ -27,7 +27,6 @@ import android.util.AttributeSet;
import android.widget.TextView;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import java.util.Calendar;
import java.util.Locale;
@@ -111,6 +110,28 @@ public class AnimatableClockView extends TextView {
super.onDetachedFromWindow();
}
+ int getDozingWeight() {
+ if (useBoldedVersion()) {
+ return mDozingWeight + 100;
+ }
+ return mDozingWeight;
+ }
+
+ int getLockScreenWeight() {
+ if (useBoldedVersion()) {
+ return mLockScreenWeight + 100;
+ }
+ return mLockScreenWeight;
+ }
+
+ /**
+ * Whether to use a bolded version based on the user specified fontWeightAdjustment.
+ */
+ boolean useBoldedVersion() {
+ // "Bold text" fontWeightAdjustment is 300.
+ return getResources().getConfiguration().fontWeightAdjustment > 100;
+ }
+
void refreshTime() {
mTime.setTimeInMillis(System.currentTimeMillis());
setText(DateFormat.format(mFormat, mTime));
@@ -162,7 +183,7 @@ public class AnimatableClockView extends TextView {
}
setTextStyle(
- mDozingWeight,
+ getDozingWeight(),
-1 /* text size, no update */,
mLockScreenColor,
false /* animate */,
@@ -171,7 +192,7 @@ public class AnimatableClockView extends TextView {
null /* onAnimationEnd */);
setTextStyle(
- mLockScreenWeight,
+ getLockScreenWeight(),
-1 /* text size, no update */,
mLockScreenColor,
true, /* animate */
@@ -180,35 +201,22 @@ public class AnimatableClockView extends TextView {
null /* onAnimationEnd */);
}
- void animateDisappear() {
- if (mTextAnimator == null) {
- return;
- }
-
- setTextStyle(
- 0 /* weight */,
- -1 /* text size, no update */,
- null /* color, no update */,
- true /* animate */,
- KeyguardBypassController.BYPASS_FADE_DURATION /* duration */,
- 0 /* delay */,
- null /* onAnimationEnd */);
- }
-
void animateCharge(DozeStateGetter dozeStateGetter) {
if (mTextAnimator == null || mTextAnimator.isRunning()) {
// Skip charge animation if dozing animation is already playing.
return;
}
Runnable startAnimPhase2 = () -> setTextStyle(
- dozeStateGetter.isDozing() ? mDozingWeight : mLockScreenWeight/* weight */,
+ dozeStateGetter.isDozing() ? getDozingWeight() : getLockScreenWeight() /* weight */,
-1,
null,
true /* animate */,
CHARGE_ANIM_DURATION_PHASE_1,
0 /* delay */,
null /* onAnimationEnd */);
- setTextStyle(dozeStateGetter.isDozing() ? mLockScreenWeight : mDozingWeight/* weight */,
+ setTextStyle(dozeStateGetter.isDozing()
+ ? getLockScreenWeight()
+ : getDozingWeight()/* weight */,
-1,
null,
true /* animate */,
@@ -218,7 +226,7 @@ public class AnimatableClockView extends TextView {
}
void animateDoze(boolean isDozing, boolean animate) {
- setTextStyle(isDozing ? mDozingWeight : mLockScreenWeight /* weight */,
+ setTextStyle(isDozing ? getDozingWeight() : getLockScreenWeight() /* weight */,
-1,
isDozing ? mDozingColor : mLockScreenColor,
animate,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 1931c0a1645c..905495d369a0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -167,7 +167,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mBroadcastDispatcher,
mBatteryController,
mKeyguardUpdateMonitor,
- mBypassController,
mResources);
mClockViewController.init();
@@ -178,7 +177,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mBroadcastDispatcher,
mBatteryController,
mKeyguardUpdateMonitor,
- mBypassController,
mResources);
mLargeClockViewController.init();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index c7be3ce01c54..88476398e09d 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -43,6 +43,7 @@ import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -85,7 +86,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
private static final float sDefaultDensity =
(float) DisplayMetrics.DENSITY_DEVICE_STABLE / (float) DisplayMetrics.DENSITY_DEFAULT;
private static final int sLockIconRadiusPx = (int) (sDefaultDensity * 36);
- private static final float sDistAboveKgBottomAreaPx = sDefaultDensity * 12;
private static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -126,7 +126,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
private boolean mUdfpsSupported;
private float mHeightPixels;
private float mWidthPixels;
- private int mBottomPadding; // in pixels
+ private int mBottomPaddingPx;
private boolean mShowUnlockIcon;
private boolean mShowLockIcon;
@@ -347,11 +347,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
}
private void updateConfiguration() {
- final DisplayMetrics metrics = mView.getContext().getResources().getDisplayMetrics();
- mWidthPixels = metrics.widthPixels;
- mHeightPixels = metrics.heightPixels;
- mBottomPadding = mView.getContext().getResources().getDimensionPixelSize(
- R.dimen.lock_icon_margin_bottom);
+ WindowManager windowManager = getContext().getSystemService(WindowManager.class);
+ Rect bounds = windowManager.getCurrentWindowMetrics().getBounds();
+ mWidthPixels = bounds.right;
+ mHeightPixels = bounds.bottom;
+ mBottomPaddingPx = getResources().getDimensionPixelSize(R.dimen.lock_icon_margin_bottom);
mUnlockedLabel = mView.getContext().getResources().getString(
R.string.accessibility_unlock_button);
@@ -370,8 +370,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
} else {
mView.setCenterLocation(
new PointF(mWidthPixels / 2,
- mHeightPixels - mBottomPadding - sDistAboveKgBottomAreaPx
- - sLockIconRadiusPx), sLockIconRadiusPx);
+ mHeightPixels - mBottomPaddingPx - sLockIconRadiusPx),
+ sLockIconRadiusPx);
}
mView.getHitRect(mSensorTouchLocation);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 1eef6e87cec0..bc023cc892a6 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -1518,6 +1518,9 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
@Override
public void onNavigationModeChanged(int mode) {
mNavBarMode = mode;
+ // update assistant entry points on system navigation radio button click
+ updateAssistantEntrypoints();
+
if (!QuickStepContract.isGesturalMode(mode)) {
// Reset the override alpha
if (getBarTransitions() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 4f3bbdbff030..7ca8652e1b3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -57,21 +57,6 @@ public class KeyguardClockPositionAlgorithm {
private int mUserSwitchPreferredY;
/**
- * Whether or not there is a custom clock face on keyguard.
- */
- private boolean mHasCustomClock;
-
- /**
- * Whether or not the NSSL contains any visible notifications.
- */
- private boolean mHasVisibleNotifs;
-
- /**
- * Height of notification stack: Sum of height of each notification.
- */
- private int mNotificationStackHeight;
-
- /**
* Minimum top margin to avoid overlap with status bar, lock icon, or multi-user switcher
* avatar.
*/
@@ -88,6 +73,16 @@ public class KeyguardClockPositionAlgorithm {
private int mContainerTopPadding;
/**
+ * Top margin of notifications introduced by presence of split shade header / status bar
+ */
+ private int mSplitShadeTopNotificationsMargin;
+
+ /**
+ * Target margin for notifications and clock from the top of the screen in split shade
+ */
+ private int mSplitShadeTargetTopMargin;
+
+ /**
* @see NotificationPanelViewController#getExpandedFraction()
*/
private float mPanelExpansion;
@@ -152,6 +147,10 @@ public class KeyguardClockPositionAlgorithm {
public void loadDimens(Resources res) {
mStatusViewBottomMargin = res.getDimensionPixelSize(
R.dimen.keyguard_status_view_bottom_margin);
+ mSplitShadeTopNotificationsMargin =
+ res.getDimensionPixelSize(R.dimen.split_shade_header_height);
+ mSplitShadeTargetTopMargin =
+ res.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin);
mContainerTopPadding =
res.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
@@ -214,7 +213,7 @@ public class KeyguardClockPositionAlgorithm {
if (mBypassEnabled) {
return (int) (mUnlockedStackScrollerPadding + mOverStretchAmount);
} else if (mIsSplitShade) {
- return clockYPosition;
+ return Math.max(0, clockYPosition - mSplitShadeTopNotificationsMargin);
} else {
return clockYPosition + mKeyguardStatusHeight;
}
@@ -224,14 +223,18 @@ public class KeyguardClockPositionAlgorithm {
if (mBypassEnabled) {
return mUnlockedStackScrollerPadding;
} else if (mIsSplitShade) {
- return mMinTopMargin;
+ return Math.max(mSplitShadeTargetTopMargin, mMinTopMargin);
} else {
return mMinTopMargin + mKeyguardStatusHeight;
}
}
private int getExpandedPreferredClockY() {
- return mMinTopMargin + mUserSwitchHeight;
+ if (mIsSplitShade) {
+ return Math.max(mSplitShadeTargetTopMargin, mMinTopMargin);
+ } else {
+ return mMinTopMargin;
+ }
}
public int getLockscreenStatusViewHeight() {
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 994aebbea01b..988034f9c5fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -3558,7 +3558,12 @@ public class NotificationPanelViewController extends PanelViewController {
mNotificationStackScrollLayoutController.setPulsing(pulsing, animatePulse);
}
- public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) {
+ public void setAmbientIndicationTop(int ambientIndicationTop, boolean ambientTextVisible) {
+ int ambientIndicationBottomPadding = 0;
+ if (ambientTextVisible) {
+ int stackBottom = mNotificationStackScrollLayoutController.getView().getBottom();
+ ambientIndicationBottomPadding = stackBottom - ambientIndicationTop;
+ }
if (mAmbientIndicationBottomPadding != ambientIndicationBottomPadding) {
mAmbientIndicationBottomPadding = ambientIndicationBottomPadding;
updateMaxDisplayedNotifications(true);
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index cd5865f58c85..426bc91a606d 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -259,8 +259,13 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
reevaluateSystemTheme(true /* forceReload */);
} else if (Intent.ACTION_WALLPAPER_CHANGED.equals(intent.getAction())) {
- mAcceptColorEvents = true;
- Log.i(TAG, "Allowing color events again");
+ if (intent.getBooleanExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, false)) {
+ mAcceptColorEvents = true;
+ Log.i(TAG, "Wallpaper changed, allowing color events again");
+ } else {
+ Log.i(TAG, "Wallpaper changed from background app, "
+ + "keep deferring color events. Accepting: " + mAcceptColorEvents);
+ }
}
}
};
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
index 209df6b54f8f..d4c3840356d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
@@ -86,7 +86,14 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
assertFalse(dialog.isShowing)
assertFalse(dialog.onStopCalled)
- runOnMainThreadAndWaitForIdleSync { dialog.dismiss() }
+ runOnMainThreadAndWaitForIdleSync {
+ // TODO(b/204561691): Remove this call to disableAllCurrentDialogsExitAnimations() and
+ // make sure that the test still pass on git_master/cf_x86_64_phone-userdebug in
+ // Forrest.
+ dialogLaunchAnimator.disableAllCurrentDialogsExitAnimations()
+
+ dialog.dismiss()
+ }
assertFalse(hostDialog.isShowing)
assertFalse(dialog.isShowing)
assertTrue(hostDialog.wasDismissed)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/AnimatableClockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/AnimatableClockControllerTest.java
index df112840ed87..5a4bb86dba45 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/AnimatableClockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/AnimatableClockControllerTest.java
@@ -40,7 +40,6 @@ import com.android.settingslib.Utils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.BatteryController;
import org.junit.After;
@@ -69,8 +68,6 @@ public class AnimatableClockControllerTest extends SysuiTestCase {
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
- private KeyguardBypassController mBypassController;
- @Mock
private Resources mResources;
private MockitoSession mStaticMockSession;
@@ -99,7 +96,6 @@ public class AnimatableClockControllerTest extends SysuiTestCase {
mBroadcastDispatcher,
mBatteryController,
mKeyguardUpdateMonitor,
- mBypassController,
mResources
);
mAnimatableClockController.init();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
index d64319b278b4..e01583e1cb1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -32,6 +32,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
+import android.graphics.Rect;
import android.graphics.drawable.AnimatedStateListDrawable;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.SensorLocationInternal;
@@ -39,10 +40,10 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Vibrator;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.util.DisplayMetrics;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import androidx.test.filters.SmallTest;
@@ -70,6 +71,7 @@ import com.airbnb.lottie.LottieAnimationView;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
@@ -88,7 +90,7 @@ public class LockIconViewControllerTest extends SysuiTestCase {
private @Mock AnimatedStateListDrawable mIconDrawable;
private @Mock Context mContext;
private @Mock Resources mResources;
- private @Mock DisplayMetrics mDisplayMetrics;
+ private @Mock(answer = Answers.RETURNS_DEEP_STUBS) WindowManager mWindowManager;
private @Mock StatusBarStateController mStatusBarStateController;
private @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private @Mock KeyguardViewController mKeyguardViewController;
@@ -137,7 +139,9 @@ public class LockIconViewControllerTest extends SysuiTestCase {
when(mLockIconView.getContext()).thenReturn(mContext);
when(mLockIconView.findViewById(R.layout.udfps_aod_lock_icon)).thenReturn(mAodFp);
when(mContext.getResources()).thenReturn(mResources);
- when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
+ when(mContext.getSystemService(WindowManager.class)).thenReturn(mWindowManager);
+ Rect windowBounds = new Rect(0, 0, 800, 1200);
+ when(mWindowManager.getCurrentWindowMetrics().getBounds()).thenReturn(windowBounds);
when(mResources.getString(R.string.accessibility_unlock_button)).thenReturn(UNLOCKED_LABEL);
when(mResources.getDrawable(anyInt(), any())).thenReturn(mIconDrawable);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 624bedc30be9..11826954baee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -263,6 +263,34 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
}
@Test
+ public void clockPositionedDependingOnMarginInSplitShade() {
+ when(mResources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin))
+ .thenReturn(400);
+ mClockPositionAlgorithm.loadDimens(mResources);
+ givenLockScreen();
+ mIsSplitShade = true;
+ // WHEN the position algorithm is run
+ positionClock();
+
+ assertThat(mClockPosition.clockY).isEqualTo(400);
+ }
+
+ @Test
+ public void notifPaddingMakesUpToFullMarginInSplitShade() {
+ when(mResources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin))
+ .thenReturn(100);
+ when(mResources.getDimensionPixelSize(R.dimen.split_shade_header_height))
+ .thenReturn(70);
+ mClockPositionAlgorithm.loadDimens(mResources);
+ givenLockScreen();
+ mIsSplitShade = true;
+ // WHEN the position algorithm is run
+ positionClock();
+ // THEN the notif padding makes up lacking margin (margin - header height = 30).
+ assertThat(mClockPosition.stackScrollerPadding).isEqualTo(30);
+ }
+
+ @Test
public void notifPaddingExpandedAlignedWithClockInSplitShadeMode() {
givenLockScreen();
mIsSplitShade = true;
@@ -271,7 +299,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
positionClock();
// THEN the padding DOESN'T adjust for keyguard status height.
assertThat(mClockPosition.stackScrollerPaddingExpanded)
- .isEqualTo(mClockPosition.clockYFullyDozing);
+ .isEqualTo(mClockPosition.clockY);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index f89bbe898e35..766471b9a695 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -152,7 +152,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
}
@Test
- public void onWallpaperColorsChanged_setsTheme() {
+ public void onWallpaperColorsChanged_setsTheme_whenForeground() {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
@@ -180,13 +180,43 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
// But should change theme after changing wallpapers
clearInvocations(mThemeOverlayApplier);
- mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
+ Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
+ intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, true);
+ mBroadcastReceiver.getValue().onReceive(null, intent);
mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
null, null), WallpaperManager.FLAG_SYSTEM);
verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
}
@Test
+ public void onWallpaperColorsChanged_setsTheme_skipWhenBackground() {
+ // Should ask for a new theme when wallpaper colors change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays =
+ ArgumentCaptor.forClass(Map.class);
+
+ verify(mThemeOverlayApplier)
+ .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
+
+ // Assert that we received the colors that we were expecting
+ assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
+ .isEqualTo(new OverlayIdentifier("ffff0000"));
+ assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_ACCENT_COLOR))
+ .isEqualTo(new OverlayIdentifier("ffff0000"));
+
+ // Should not change theme after changing wallpapers, if intent doesn't have
+ // WallpaperManager.EXTRA_FROM_FOREGROUND_APP set to true.
+ clearInvocations(mThemeOverlayApplier);
+ mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
+ mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
+ null, null), WallpaperManager.FLAG_SYSTEM);
+ verify(mThemeOverlayApplier, never())
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ }
+
+ @Test
public void onWallpaperColorsChanged_preservesWallpaperPickerTheme() {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
@@ -455,7 +485,9 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
// Regression test: null events should not reset the internal state and allow colors to be
// applied again.
clearInvocations(mThemeOverlayApplier);
- mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
+ Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
+ intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, true);
+ mBroadcastReceiver.getValue().onReceive(null, intent);
mColorsListener.getValue().onColorsChanged(null, WallpaperManager.FLAG_SYSTEM);
verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(),
any());
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 319fa94058dd..429696fd88a2 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -421,10 +421,10 @@ class UserController implements Handler.Callback {
void setStopUserOnSwitch(@StopUserOnSwitch int value) {
if (mInjector.checkCallingPermission(android.Manifest.permission.MANAGE_USERS)
== PackageManager.PERMISSION_DENIED && mInjector.checkCallingPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ android.Manifest.permission.INTERACT_ACROSS_USERS)
== PackageManager.PERMISSION_DENIED) {
throw new SecurityException(
- "You either need MANAGE_USERS or INTERACT_ACROSS_USERS_FULL permission to "
+ "You either need MANAGE_USERS or INTERACT_ACROSS_USERS permission to "
+ "call setStopUserOnSwitch()");
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index a3b5e79cc8c7..fadaf1082e46 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2862,14 +2862,31 @@ public final class DisplayManagerService extends SystemService {
@Override // Binder call
public void setBrightnessConfigurationForUser(
BrightnessConfiguration c, @UserIdInt int userId, String packageName) {
- mLogicalDisplayMapper.forEachLocked(logicalDisplay -> {
- if (logicalDisplay.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) {
- return;
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS,
+ "Permission required to change the display's brightness configuration");
+ if (userId != UserHandle.getCallingUserId()) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ "Permission required to change the display brightness"
+ + " configuration of another user");
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mSyncRoot) {
+ mLogicalDisplayMapper.forEachLocked(logicalDisplay -> {
+ if (logicalDisplay.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) {
+ return;
+ }
+ final DisplayDevice displayDevice =
+ logicalDisplay.getPrimaryDisplayDeviceLocked();
+ setBrightnessConfigurationForDisplayInternal(c, displayDevice.getUniqueId(),
+ userId, packageName);
+ });
}
- final DisplayDevice displayDevice = logicalDisplay.getPrimaryDisplayDeviceLocked();
- setBrightnessConfigurationForDisplay(c, displayDevice.getUniqueId(), userId,
- packageName);
- });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 2f550c6e9338..47d8022a5acc 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -7699,7 +7699,10 @@ public class NotificationManagerService extends SystemService {
final int waitMs = mAudioManager.getFocusRampTimeMs(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
record.getAudioAttributes());
- if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
+ if (DBG) {
+ Slog.v(TAG, "Delaying vibration for notification "
+ + record.getKey() + " by " + waitMs + "ms");
+ }
try {
Thread.sleep(waitMs);
} catch (InterruptedException e) { }
@@ -7707,9 +7710,17 @@ public class NotificationManagerService extends SystemService {
// so need to check the notification still valide for vibrate.
synchronized (mNotificationLock) {
if (mNotificationsByKey.get(record.getKey()) != null) {
- vibrate(record, effect, true);
+ if (record.getKey().equals(mVibrateNotificationKey)) {
+ vibrate(record, effect, true);
+ } else {
+ if (DBG) {
+ Slog.v(TAG, "No vibration for notification "
+ + record.getKey() + ": a new notification is "
+ + "vibrating, or effects were cleared while waiting");
+ }
+ }
} else {
- Slog.e(TAG, "No vibration for canceled notification : "
+ Slog.w(TAG, "No vibration for canceled notification "
+ record.getKey());
}
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index a51ed09790a4..2f353d19b5df 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.wallpaper;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.app.WallpaperManager.COMMAND_REAPPLY;
import static android.app.WallpaperManager.FLAG_LOCK;
import static android.app.WallpaperManager.FLAG_SYSTEM;
@@ -791,6 +792,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
private final Context mContext;
private final WindowManagerInternal mWindowManagerInternal;
private final IPackageManager mIPackageManager;
+ private final ActivityManager mActivityManager;
private final MyPackageMonitor mMonitor;
private final AppOpsManager mAppOpsManager;
@@ -939,6 +941,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
*/
WallpaperColors primaryColors;
+ /**
+ * If the wallpaper was set from a foreground app (instead of from a background service).
+ */
+ public boolean fromForegroundApp;
+
WallpaperConnection connection;
long lastDiedTime;
boolean wallpaperUpdating;
@@ -1688,6 +1695,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mDisplayManager.registerDisplayListener(mDisplayListener, null /* handler */);
+ mActivityManager = mContext.getSystemService(ActivityManager.class);
mMonitor = new MyPackageMonitor();
mColorsChangedListeners = new SparseArray<>();
@@ -2648,6 +2656,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
+ final boolean fromForegroundApp = Binder.withCleanCallingIdentity(() ->
+ mActivityManager.getPackageImportance(callingPackage) == IMPORTANCE_FOREGROUND);
+
synchronized (mLock) {
if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
WallpaperData wallpaper;
@@ -2670,6 +2681,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
wallpaper.imageWallpaperPending = true;
wallpaper.whichPending = which;
wallpaper.setComplete = completion;
+ wallpaper.fromForegroundApp = fromForegroundApp;
wallpaper.cropHint.set(cropHint);
wallpaper.allowBackup = allowBackup;
}
@@ -3052,6 +3064,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
wallpaper.callbacks.finishBroadcast();
final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
+ intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, wallpaper.fromForegroundApp);
mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 4190ff0b9bc7..1b7a012094f6 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1126,7 +1126,11 @@ class Task extends TaskFragment {
if (inMultiWindowMode() || !hasChild()) return false;
if (intent != null) {
final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME;
- return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags;
+ final Task task = getDisplayArea() != null ? getDisplayArea().getRootHomeTask() : null;
+ final boolean isLockTaskModeViolation = task != null
+ && mAtmService.getLockTaskController().isLockTaskModeViolation(task);
+ return (intent.getFlags() & returnHomeFlags) == returnHomeFlags
+ && !isLockTaskModeViolation;
}
final Task bottomTask = getBottomMostTask();
return bottomTask != this && bottomTask.returnsToHomeRootTask();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 3ac30d0258a5..cadc81600bbb 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -51,6 +51,7 @@ import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
@@ -184,6 +185,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
public DevicePolicyManager parentDpm;
public DevicePolicyManagerServiceTestable dpms;
+ private boolean mIsAutomotive;
+
/*
* The CA cert below is the content of cacert.pem as generated by:
*
@@ -266,6 +269,9 @@ public class DevicePolicyManagerTest extends DpmTestBase {
setUpUserManager();
when(getServices().lockPatternUtils.hasSecureLockScreen()).thenReturn(true);
+
+ mIsAutomotive = mContext.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
}
private TransferOwnershipMetadataManager getMockTransferMetadataManager() {
@@ -2117,10 +2123,13 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertThat(dpm.getPasswordExpirationTimeout(admin1))
.isEqualTo(originalPasswordExpirationTimeout);
- int originalPasswordQuality = dpm.getPasswordQuality(admin1);
- assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC));
- assertThat(dpm.getPasswordQuality(admin1)).isEqualTo(originalPasswordQuality);
+ if (isDeprecatedPasswordApisSupported()) {
+ int originalPasswordQuality = dpm.getPasswordQuality(admin1);
+ assertExpectException(SecurityException.class, /* messageRegex= */ null,
+ () -> dpm.setPasswordQuality(admin1,
+ DevicePolicyManager.PASSWORD_QUALITY_NUMERIC));
+ assertThat(dpm.getPasswordQuality(admin1)).isEqualTo(originalPasswordQuality);
+ }
}
@Test
@@ -5231,6 +5240,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testIsActivePasswordSufficient() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
mContext.packageName = admin1.getPackageName();
setupDeviceOwner();
@@ -5283,6 +5294,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testIsActivePasswordSufficient_noLockScreen() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
// If there is no lock screen, the password is considered empty no matter what, because
// it provides no security.
when(getServices().lockPatternUtils.hasSecureLockScreen()).thenReturn(false);
@@ -5363,6 +5376,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testGetAggregatedPasswordMetrics_IgnoreProfileRequirement()
throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
final int managedProfileUserId = CALLER_USER_HANDLE;
final int managedProfileAdminUid =
UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
@@ -5392,6 +5407,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testCanSetPasswordRequirementOnParentPreS() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
final int managedProfileUserId = CALLER_USER_HANDLE;
final int managedProfileAdminUid =
UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
@@ -5407,6 +5424,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testCannotSetPasswordRequirementOnParent() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
final int managedProfileUserId = CALLER_USER_HANDLE;
final int managedProfileAdminUid =
UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
@@ -5427,6 +5446,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void isActivePasswordSufficient_SeparateWorkChallenge_ProfileQualityRequirementMet()
throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
// Create work profile with empty separate challenge
final int managedProfileUserId = 15;
final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
@@ -5450,6 +5471,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void isActivePasswordSufficient_SeparateWorkChallenge_ProfileComplexityRequirementMet()
throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
// Create work profile with empty separate challenge
final int managedProfileUserId = 15;
final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
@@ -5473,6 +5496,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void isActivePasswordSufficient_SeparateWorkChallenge_ParentQualityRequirementMet()
throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
// Create work profile with empty separate challenge
final int managedProfileUserId = 15;
final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
@@ -5519,6 +5544,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void isActivePasswordSufficient_UnifiedWorkChallenge_ProfileQualityRequirementMet()
throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
// Create work profile with unified challenge
final int managedProfileUserId = 15;
final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
@@ -5565,6 +5592,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void isActivePasswordSufficient_UnifiedWorkChallenge_ParentQualityRequirementMet()
throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
// Create work profile with unified challenge
final int managedProfileUserId = 15;
final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
@@ -5625,6 +5654,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testPasswordQualityAppliesToParentPreS() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
final int managedProfileUserId = CALLER_USER_HANDLE;
final int managedProfileAdminUid =
UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
@@ -7285,6 +7316,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexity_UnauthorizedCallersOnDO() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
// DO must be able to set it.
@@ -7300,6 +7333,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexity_UnauthorizedCallersOnPO() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
setupProfileOwner();
// PO must be able to set it.
@@ -7314,6 +7349,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexity_validValuesOnly() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
setupProfileOwner();
@@ -7335,6 +7372,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexity_setAndGet() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
setupProfileOwner();
@@ -7348,6 +7387,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexityOnParent_setAndGet() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
final int managedProfileUserId = 15;
final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
@@ -7366,6 +7407,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexity_isSufficient() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
mContext.packageName = admin1.getPackageName();
setupDeviceOwner();
@@ -7395,6 +7438,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexity_resetBySettingQuality() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
setupProfileOwner();
@@ -7407,6 +7452,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexity_overridesQuality() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
setupProfileOwner();
@@ -7421,6 +7468,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexityFailsWithQualityOnParent() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
final int managedProfileUserId = CALLER_USER_HANDLE;
final int managedProfileAdminUid =
UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
@@ -7435,6 +7484,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetQualityOnParentFailsWithComplexityOnProfile() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
final int managedProfileUserId = CALLER_USER_HANDLE;
final int managedProfileAdminUid =
UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
@@ -8015,4 +8066,13 @@ public class DevicePolicyManagerTest extends DpmTestBase {
when(mContext.getResources().getStringArray(R.array.vendor_policy_exempt_apps))
.thenReturn(new String[0]);
}
+
+ private boolean isDeprecatedPasswordApisSupported() {
+ return !mIsAutomotive;
+ }
+
+ private void assumeDeprecatedPasswordApisSupported() {
+ assumeTrue("device doesn't support deprecated password APIs",
+ isDeprecatedPasswordApisSupported());
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index ea46eab6e8f9..d593e8000048 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -32,7 +32,6 @@ import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
@@ -40,6 +39,7 @@ import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.after;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -48,6 +48,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.Notification;
@@ -73,7 +74,6 @@ import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Slog;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
@@ -102,6 +102,7 @@ import java.util.Objects;
@SmallTest
@RunWith(AndroidJUnit4.class)
+@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
public class BuzzBeepBlinkTest extends UiServiceTestCase {
@Mock AudioManager mAudioManager;
@@ -156,6 +157,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
+ when(mAudioManager.getFocusRampTimeMs(anyInt(), any(AudioAttributes.class))).thenReturn(50);
when(mUsageStats.isAlertRateLimited(any())).thenReturn(false);
when(mVibrator.hasFrequencyControl()).thenReturn(false);
when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
@@ -444,6 +446,11 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
timeout(MAX_VIBRATION_DELAY).times(1));
}
+ private void verifyDelayedNeverVibrate() {
+ verify(mVibrator, after(MAX_VIBRATION_DELAY).never()).vibrate(anyInt(), anyString(), any(),
+ anyString(), any(AudioAttributes.class));
+ }
+
private void verifyVibrate(ArgumentMatcher<VibrationEffect> effectMatcher,
VerificationMode verification) {
ArgumentCaptor<AudioAttributes> captor = ArgumentCaptor.forClass(AudioAttributes.class);
@@ -1588,8 +1595,51 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
// beep wasn't reset
verifyNeverBeep();
verifyNeverVibrate();
- verify(mRingtonePlayer, never()).stopAsync();
- verify(mVibrator, never()).cancel();
+ verifyNeverStopAudio();
+ verifyNeverStopVibrate();
+ }
+
+ @Test
+ public void testRingtoneInsistentBeep_clearEffectsStopsSoundAndVibration() throws Exception {
+ NotificationChannel ringtoneChannel =
+ new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
+ ringtoneChannel.setSound(Uri.fromParts("a", "b", "c"),
+ new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
+ ringtoneChannel.enableVibration(true);
+ NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
+ mService.addNotification(ringtoneNotification);
+ assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
+ mService.buzzBeepBlinkLocked(ringtoneNotification);
+ verifyBeepLooped();
+ verifyDelayedVibrateLooped();
+
+ mService.clearSoundLocked();
+ mService.clearVibrateLocked();
+
+ verifyStopAudio();
+ verifyStopVibrate();
+ }
+
+ @Test
+ public void testRingtoneInsistentBeep_neverVibratesWhenEffectsClearedBeforeDelay()
+ throws Exception {
+ NotificationChannel ringtoneChannel =
+ new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
+ ringtoneChannel.setSound(Uri.fromParts("a", "b", "c"),
+ new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
+ ringtoneChannel.enableVibration(true);
+ NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
+ mService.addNotification(ringtoneNotification);
+ assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
+ mService.buzzBeepBlinkLocked(ringtoneNotification);
+ verifyBeepLooped();
+ verifyNeverVibrate();
+
+ mService.clearSoundLocked();
+ mService.clearVibrateLocked();
+
+ verifyStopAudio();
+ verifyDelayedNeverVibrate();
}
@Test
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 54d3af520d3c..4d2e00785d49 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3893,6 +3893,30 @@ public class CarrierConfigManager {
public static final String KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL =
"enabled_4g_opportunistic_network_scan_bool";
+ /**
+ * Only relevant when the device supports opportunistic networks but does not support
+ * simultaneuous 5G+5G. Controls how long, in milliseconds, to wait before opportunistic network
+ * goes out of service before switching the 5G capability back to primary stack. The idea of
+ * waiting a few seconds is to minimize the calling of the expensive capability switching
+ * operation in the case where CBRS goes back into service shortly after going out of it.
+ *
+ * @hide
+ */
+ public static final String KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG =
+ "time_to_switch_back_to_primary_if_opportunistic_oos_long";
+
+ /**
+ * Only relevant when the device supports opportunistic networks but does not support
+ * simultaneuous 5G+5G. Controls how long, in milliseconds, after 5G capability has switched back
+ * to primary stack due to opportunistic network being OOS. The idea is to minimizing the
+ * 'ping-ponging' effect where device is constantly witching capability back and forth between
+ * primary and opportunistic stack.
+ *
+ * @hide
+ */
+ public static final String KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG
+ = "opportunistic_time_to_scan_after_capability_switch_to_primary_long";
+
/**
* Indicates zero or more emergency number prefix(es), because some carrier requires
* if users dial an emergency number address with a specific prefix, the combination of the
@@ -5766,6 +5790,10 @@ public class CarrierConfigManager {
/* Default value is 2 seconds. */
sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 2000);
sDefaults.putBoolean(KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL, true);
+ sDefaults.putInt(KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG, 60000);
+ sDefaults.putInt(
+ KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG,
+ 120000);
sDefaults.putAll(Gps.getDefaults());
sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
new int[] {