summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/system-current.txt3
-rw-r--r--core/api/test-current.txt3
-rw-r--r--core/java/android/app/ActivityManager.java78
-rw-r--r--core/java/android/app/TaskInfo.java11
-rw-r--r--core/java/android/os/Environment.java13
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java14
-rw-r--r--core/java/android/widget/ToastPresenter.java44
-rw-r--r--core/jni/android_content_res_ApkAssets.cpp2
-rw-r--r--core/jni/android_view_InputEventSender.cpp8
-rw-r--r--core/res/res/values/config.xml2
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--data/etc/car/com.android.car.developeroptions.xml3
-rw-r--r--data/etc/car/com.android.car.xml1
-rw-r--r--data/etc/car/com.google.android.car.kitchensink.xml4
-rw-r--r--graphics/java/android/graphics/Point.java22
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/ToastPlugin.java5
-rw-r--r--packages/SystemUI/res/drawable/toast_background.xml21
-rw-r--r--packages/SystemUI/res/layout/text_toast.xml51
-rw-r--r--packages/SystemUI/res/values-land/dimens.xml2
-rw-r--r--packages/SystemUI/res/values/dimens.xml7
-rw-r--r--packages/SystemUI/res/values/flags.xml2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java21
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java153
-rw-r--r--packages/SystemUI/src/com/android/systemui/BatteryMeterView.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java136
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt105
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/ToastUI.java150
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java18
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java47
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java5
-rw-r--r--services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java1
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java23
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java17
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java3
-rw-r--r--services/core/java/com/android/server/wm/Task.java72
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java39
-rw-r--r--services/java/com/android/server/SystemServer.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java85
43 files changed, 887 insertions, 406 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index dffa0cc315ae..bfdce373a47e 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -338,9 +338,8 @@ package android {
field public static final int config_helpPackageNameKey = 17039387; // 0x104001b
field public static final int config_helpPackageNameValue = 17039388; // 0x104001c
field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
- field public static final int config_systemAutomotiveProjection = 17039402; // 0x104002a
+ field public static final int config_systemAutomotiveProjection = 17039401; // 0x1040029
field public static final int config_systemGallery = 17039399; // 0x1040027
- field public static final int config_systemVideoCall = 17039401; // 0x1040029
}
public static final class R.style {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 5d0cea56a2d4..06110319cb35 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -54,9 +54,8 @@ package android {
field public static final int config_defaultAssistant = 17039393; // 0x1040021
field public static final int config_defaultDialer = 17039395; // 0x1040023
field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
- field public static final int config_systemAutomotiveProjection = 17039402; // 0x104002a
+ field public static final int config_systemAutomotiveProjection = 17039401; // 0x1040029
field public static final int config_systemGallery = 17039399; // 0x1040027
- field public static final int config_systemVideoCall = 17039401; // 0x1040029
}
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 43d0269beae2..e2426d116319 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -50,7 +50,9 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Point;
+import android.graphics.Rect;
import android.graphics.drawable.Icon;
+import android.hardware.HardwareBuffer;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Build;
@@ -76,6 +78,7 @@ import android.util.Singleton;
import android.util.Size;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
+import android.window.TaskSnapshot;
import com.android.internal.app.LocalePicker;
import com.android.internal.app.procstats.ProcessStats;
@@ -1740,6 +1743,62 @@ public class ActivityManager {
*/
public static class RecentTaskInfo extends TaskInfo implements Parcelable {
/**
+ * @hide
+ */
+ public static class PersistedTaskSnapshotData {
+ /**
+ * The bounds of the task when the last snapshot was taken, may be null if the task is
+ * not yet attached to the hierarchy.
+ * @see {@link android.window.TaskSnapshot#mTaskSize}.
+ * @hide
+ */
+ public @Nullable Point taskSize;
+
+ /**
+ * The content insets of the task when the task snapshot was taken.
+ * @see {@link android.window.TaskSnapshot#mContentInsets}.
+ * @hide
+ */
+ public @Nullable Rect contentInsets;
+
+ /**
+ * The size of the last snapshot taken, may be null if there is no associated snapshot.
+ * @see {@link android.window.TaskSnapshot#mSnapshot}.
+ * @hide
+ */
+ public @Nullable Point bufferSize;
+
+ /**
+ * Sets the data from the other data.
+ * @hide
+ */
+ public void set(PersistedTaskSnapshotData other) {
+ taskSize = other.taskSize;
+ contentInsets = other.contentInsets;
+ bufferSize = other.bufferSize;
+ }
+
+ /**
+ * Sets the data from the provided {@param snapshot}.
+ * @hide
+ */
+ public void set(TaskSnapshot snapshot) {
+ if (snapshot == null) {
+ taskSize = null;
+ contentInsets = null;
+ bufferSize = null;
+ return;
+ }
+ final HardwareBuffer buffer = snapshot.getHardwareBuffer();
+ taskSize = new Point(snapshot.getTaskSize());
+ contentInsets = new Rect(snapshot.getContentInsets());
+ bufferSize = buffer != null
+ ? new Point(buffer.getWidth(), buffer.getHeight())
+ : null;
+ }
+ }
+
+ /**
* If this task is currently running, this is the identifier for it.
* If it is not running, this will be -1.
*
@@ -1782,6 +1841,12 @@ public class ActivityManager {
*/
public ArrayList<RecentTaskInfo> childrenTaskInfos = new ArrayList<>();
+ /**
+ * Information about the last snapshot taken for this task.
+ * @hide
+ */
+ public PersistedTaskSnapshotData lastSnapshotData = new PersistedTaskSnapshotData();
+
public RecentTaskInfo() {
}
@@ -1798,6 +1863,9 @@ public class ActivityManager {
id = source.readInt();
persistentId = source.readInt();
childrenTaskInfos = source.readArrayList(RecentTaskInfo.class.getClassLoader());
+ lastSnapshotData.taskSize = source.readTypedObject(Point.CREATOR);
+ lastSnapshotData.contentInsets = source.readTypedObject(Rect.CREATOR);
+ lastSnapshotData.bufferSize = source.readTypedObject(Point.CREATOR);
super.readFromParcel(source);
}
@@ -1806,6 +1874,9 @@ public class ActivityManager {
dest.writeInt(id);
dest.writeInt(persistentId);
dest.writeList(childrenTaskInfos);
+ dest.writeTypedObject(lastSnapshotData.taskSize, flags);
+ dest.writeTypedObject(lastSnapshotData.contentInsets, flags);
+ dest.writeTypedObject(lastSnapshotData.bufferSize, flags);
super.writeToParcel(dest, flags);
}
@@ -1825,7 +1896,6 @@ public class ActivityManager {
public void dump(PrintWriter pw, String indent) {
pw.println(); pw.print(" ");
pw.print(" id="); pw.print(persistentId);
- pw.print(" stackId="); pw.print(stackId);
pw.print(" userId="); pw.print(userId);
pw.print(" hasTask="); pw.print((id != -1));
pw.print(" lastActiveTime="); pw.println(lastActiveTime);
@@ -1872,6 +1942,12 @@ public class ActivityManager {
pw.print(Integer.toHexString(td.getBackgroundColorFloating()));
pw.println(" }");
}
+ pw.print(" ");
+ pw.print(" lastSnapshotData {");
+ pw.print(" taskSize=" + lastSnapshotData.taskSize);
+ pw.print(" contentInsets=" + lastSnapshotData.contentInsets);
+ pw.print(" bufferSize=" + lastSnapshotData.bufferSize);
+ pw.println(" }");
}
}
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 390d9219ef2a..938ce0d56933 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -53,13 +53,6 @@ public class TaskInfo {
public int userId;
/**
- * The id of the ActivityStack that currently contains this task.
- * @hide
- */
- @UnsupportedAppUsage
- public int stackId;
-
- /**
* The identifier for this task.
*/
public int taskId;
@@ -358,7 +351,6 @@ public class TaskInfo {
*/
void readFromParcel(Parcel source) {
userId = source.readInt();
- stackId = source.readInt();
taskId = source.readInt();
displayId = source.readInt();
isRunning = source.readBoolean();
@@ -394,7 +386,6 @@ public class TaskInfo {
*/
void writeToParcel(Parcel dest, int flags) {
dest.writeInt(userId);
- dest.writeInt(stackId);
dest.writeInt(taskId);
dest.writeInt(displayId);
dest.writeBoolean(isRunning);
@@ -428,7 +419,7 @@ public class TaskInfo {
@Override
public String toString() {
- return "TaskInfo{userId=" + userId + " stackId=" + stackId + " taskId=" + taskId
+ return "TaskInfo{userId=" + userId + " taskId=" + taskId
+ " displayId=" + displayId
+ " isRunning=" + isRunning
+ " baseIntent=" + baseIntent + " baseActivity=" + baseActivity
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 62951246a43b..124c0b00b2b2 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -1359,8 +1359,17 @@ public class Environment {
}
final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
- return appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
- uid, context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED;
+ final String opPackageName = context.getOpPackageName();
+
+ if (appOps.noteOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, uid,
+ opPackageName) == AppOpsManager.MODE_ALLOWED) {
+ return true;
+ }
+
+ // Legacy external storage access is granted to instrumentations invoked with
+ // "--no-isolated-storage" flag.
+ return appOps.noteOpNoThrow(AppOpsManager.OP_NO_ISOLATED_STORAGE, uid,
+ opPackageName) == AppOpsManager.MODE_ALLOWED;
}
private static boolean isScopedStorageEnforced(boolean defaultScopedStorage,
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 90c8e17a6984..7b2bb73ff562 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -115,7 +115,6 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
@@ -1083,19 +1082,6 @@ public final class InputMethodManager {
}
}
- private static class ImeThreadFactory implements ThreadFactory {
- private final String mThreadName;
-
- ImeThreadFactory(String name) {
- mThreadName = name;
- }
-
- @Override
- public Thread newThread(Runnable r) {
- return new Thread(r, mThreadName);
- }
- }
-
final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
@Override
protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
diff --git a/core/java/android/widget/ToastPresenter.java b/core/java/android/widget/ToastPresenter.java
index b484dfacbf6c..2904a8c889a2 100644
--- a/core/java/android/widget/ToastPresenter.java
+++ b/core/java/android/widget/ToastPresenter.java
@@ -172,6 +172,22 @@ public class ToastPresenter {
}
/**
+ * Update the LayoutParameters of the currently showing toast view. This is used for layout
+ * updates based on orientation changes.
+ */
+ public void updateLayoutParams(int xOffset, int yOffset, float horizontalMargin,
+ float verticalMargin, int gravity) {
+ checkState(mView != null, "Toast must be showing to update its layout parameters.");
+ Configuration config = mResources.getConfiguration();
+ mParams.gravity = Gravity.getAbsoluteGravity(gravity, config.getLayoutDirection());
+ mParams.x = xOffset;
+ mParams.y = yOffset;
+ mParams.horizontalMargin = horizontalMargin;
+ mParams.verticalMargin = verticalMargin;
+ addToastView();
+ }
+
+ /**
* Sets {@link WindowManager.LayoutParams#SYSTEM_FLAG_SHOW_FOR_ALL_USERS} flag if {@code
* packageName} is a cross-user package.
*
@@ -221,18 +237,7 @@ public class ToastPresenter {
adjustLayoutParams(mParams, windowToken, duration, gravity, xOffset, yOffset,
horizontalMargin, verticalMargin, removeWindowAnimations);
- if (mView.getParent() != null) {
- mWindowManager.removeView(mView);
- }
- try {
- mWindowManager.addView(mView, mParams);
- } catch (WindowManager.BadTokenException e) {
- // Since the notification manager service cancels the token right after it notifies us
- // to cancel the toast there is an inherent race and we may attempt to add a window
- // after the token has been invalidated. Let us hedge against that.
- Log.w(TAG, "Error while attempting to show toast from " + mPackageName, e);
- return;
- }
+ addToastView();
trySendAccessibilityEvent(mView, mPackageName);
if (callback != null) {
try {
@@ -288,4 +293,19 @@ public class ToastPresenter {
view.dispatchPopulateAccessibilityEvent(event);
mAccessibilityManager.sendAccessibilityEvent(event);
}
+
+ private void addToastView() {
+ if (mView.getParent() != null) {
+ mWindowManager.removeView(mView);
+ }
+ try {
+ mWindowManager.addView(mView, mParams);
+ } catch (WindowManager.BadTokenException e) {
+ // Since the notification manager service cancels the token right after it notifies us
+ // to cancel the toast there is an inherent race and we may attempt to add a window
+ // after the token has been invalidated. Let us hedge against that.
+ Log.w(TAG, "Error while attempting to show toast from " + mPackageName, e);
+ return;
+ }
+ }
}
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index af06e2e80cec..c7439f1b32d4 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -354,7 +354,7 @@ static void NativeDestroy(void* ptr) {
}
static jlong NativeGetFinalizer(JNIEnv* /*env*/, jclass /*clazz*/) {
- return reinterpret_cast<jlong>(&NativeDestroy);
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&NativeDestroy));
}
static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index ac680f6e2611..9746a07a1b77 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -199,7 +199,13 @@ status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) {
for (;;) {
uint32_t publishedSeq;
bool handled;
- status_t status = mInputPublisher.receiveFinishedSignal(&publishedSeq, &handled);
+ std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)> callback =
+ [&publishedSeq, &handled](uint32_t inSeq, bool inHandled,
+ nsecs_t inConsumeTime) -> void {
+ publishedSeq = inSeq;
+ handled = inHandled;
+ };
+ status_t status = mInputPublisher.receiveFinishedSignal(callback);
if (status) {
if (status == WOULD_BLOCK) {
return OK;
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index beae9353a10f..09ca12aa9744 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1946,8 +1946,6 @@
<string name="config_systemAutomotiveProjection" translatable="false"></string>
<!-- The name of the package that will hold the system cluster service role. -->
<string name="config_systemAutomotiveCluster" translatable="false"></string>
- <!-- The name of the package that will hold the system video call role. -->
- <string name="config_systemVideoCall" translatable="false"></string>
<!-- The name of the package that will be allowed to change its components' label/icon. -->
<string name="config_overrideComponentUiPackage" translatable="false"></string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 40c5206b86d8..46f928df323c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3118,8 +3118,6 @@
<!-- @hide @SystemApi @TestApi -->
<public name="config_systemAutomotiveCluster" />
<!-- @hide @SystemApi @TestApi -->
- <public name="config_systemVideoCall" />
- <!-- @hide @SystemApi @TestApi -->
<public name="config_systemAutomotiveProjection" />
</public-group>
diff --git a/data/etc/car/com.android.car.developeroptions.xml b/data/etc/car/com.android.car.developeroptions.xml
index cf0199bd1b85..c9405748d7de 100644
--- a/data/etc/car/com.android.car.developeroptions.xml
+++ b/data/etc/car/com.android.car.developeroptions.xml
@@ -26,6 +26,7 @@
<permission name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS"/>
<permission name="android.permission.DELETE_PACKAGES"/>
<permission name="android.permission.FORCE_STOP_PACKAGES"/>
+ <permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/>
<permission name="android.permission.LOCAL_MAC_ADDRESS"/>
<permission name="android.permission.MANAGE_DEBUGGING"/>
<permission name="android.permission.MANAGE_FINGERPRINT"/>
@@ -40,10 +41,12 @@
<permission name="android.permission.MOVE_PACKAGE"/>
<permission name="android.permission.OVERRIDE_WIFI_CONFIG"/>
<permission name="android.permission.PACKAGE_USAGE_STATS"/>
+ <permission name="android.permission.READ_DREAM_STATE"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.READ_SEARCH_INDEXABLES"/>
<permission name="android.permission.REBOOT"/>
<permission name="android.permission.REQUEST_NETWORK_SCORES"/>
+ <permission name="android.permission.RESTART_WIFI_SUBSYSTEM"/>
<permission name="android.permission.SET_TIME"/>
<permission name="android.permission.STATUS_BAR"/>
<permission name="android.permission.TETHER_PRIVILEGED"/>
diff --git a/data/etc/car/com.android.car.xml b/data/etc/car/com.android.car.xml
index 19548bc404d1..48f6ab376c82 100644
--- a/data/etc/car/com.android.car.xml
+++ b/data/etc/car/com.android.car.xml
@@ -25,6 +25,7 @@
<permission name="android.permission.REAL_GET_TASKS"/>
<permission name="android.permission.REBOOT"/>
<permission name="android.permission.READ_LOGS"/>
+ <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml
index 3a20a9cb1695..bd30d7a61517 100644
--- a/data/etc/car/com.google.android.car.kitchensink.xml
+++ b/data/etc/car/com.google.android.car.kitchensink.xml
@@ -27,8 +27,10 @@
<permission name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
<permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
<permission name="android.permission.LOCATION_HARDWARE"/>
+ <permission name="android.permission.LOCK_DEVICE"/>
<permission name="android.permission.MANAGE_USB"/>
<permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.MASTER_CLEAR"/>
<!-- use for CarServiceTest -->
<permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
<permission name="android.permission.MODIFY_AUDIO_ROUTING"/>
@@ -40,9 +42,11 @@
<permission name="android.permission.REAL_GET_TASKS"/>
<permission name="android.permission.READ_LOGS"/>
<permission name="android.permission.REBOOT"/>
+ <permission name="android.permission.RESET_PASSWORD"/>
<permission name="android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS"/>
<!-- use for CarServiceTest -->
<permission name="android.permission.SET_ACTIVITY_WATCHER"/>
+ <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
<!-- use for rotary fragment to enable/disable packages related to rotary -->
diff --git a/graphics/java/android/graphics/Point.java b/graphics/java/android/graphics/Point.java
index cf2f970e3d58..25f76f6f6da7 100644
--- a/graphics/java/android/graphics/Point.java
+++ b/graphics/java/android/graphics/Point.java
@@ -17,6 +17,7 @@
package android.graphics;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -96,6 +97,27 @@ public class Point implements Parcelable {
}
/**
+ * @return Returns a {@link String} that represents this point which can be parsed with
+ * {@link #unflattenFromString(String)}.
+ * @hide
+ */
+ @NonNull
+ public String flattenToString() {
+ return x + "x" + y;
+ }
+
+ /**
+ * @return Returns a {@link Point} from a short string created from {@link #flattenToString()}.
+ * @hide
+ */
+ @Nullable
+ public static Point unflattenFromString(String s) throws NumberFormatException {
+ final int sep_ix = s.indexOf("x");
+ return new Point(Integer.parseInt(s.substring(0, sep_ix)),
+ Integer.parseInt(s.substring(sep_ix + 1)));
+ }
+
+ /**
* Parcelable interface methods
*/
@Override
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ToastPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ToastPlugin.java
index 0831e0ef7795..da079cf04403 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ToastPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ToastPlugin.java
@@ -103,5 +103,10 @@ public interface ToastPlugin extends Plugin {
default Animator getOutAnimation() {
return null;
}
+
+ /**
+ * Called on orientation changes.
+ */
+ default void onOrientationChange(int orientation) { }
}
}
diff --git a/packages/SystemUI/res/drawable/toast_background.xml b/packages/SystemUI/res/drawable/toast_background.xml
new file mode 100644
index 000000000000..5c45e8346e3c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/toast_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="#FFFFFFFF" />
+ <corners android:radius="@dimen/toast_bg_radius" />
+</shape>
diff --git a/packages/SystemUI/res/layout/text_toast.xml b/packages/SystemUI/res/layout/text_toast.xml
new file mode 100644
index 000000000000..de4e062805fe
--- /dev/null
+++ b/packages/SystemUI/res/layout/text_toast.xml
@@ -0,0 +1,51 @@
+<?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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxWidth="@dimen/toast_width"
+ android:orientation="horizontal"
+ android:background="@drawable/toast_background"
+ android:backgroundTint="?android:attr/colorBackground"
+ android:layout_marginEnd="16dp"
+ android:layout_marginStart="16dp"
+ android:gravity="center_vertical">
+
+ <!-- Icon should be 24x24, make slightly larger to allow for shadowing, adjust via padding -->
+ <ImageView
+ android:id="@+id/icon"
+ android:alpha="@dimen/toast_icon_alpha"
+ android:padding="11.5dp"
+ android:layout_width="@dimen/toast_icon_size"
+ android:layout_height="@dimen/toast_icon_size"/>
+ <TextView
+ android:id="@+id/text"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:paddingTop="12dp"
+ android:paddingBottom="12dp"
+ android:paddingStart="0dp"
+ android:paddingEnd="22dp"
+ android:textSize="@dimen/toast_text_size"
+ android:textColor="?android:attr/textColorPrimary"
+ android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+</LinearLayout>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 51d7b8eff5fc..24c7655e5ae4 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -52,4 +52,6 @@
<!-- (footer_height -48dp)/2 -->
<dimen name="controls_management_footer_top_margin">4dp</dimen>
<dimen name="controls_management_favorites_top_margin">8dp</dimen>
+
+ <dimen name="toast_y_offset">24dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 79471e6dacd2..08cd6553e252 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1354,4 +1354,11 @@
<dimen name="rounded_slider_icon_size">24dp</dimen>
<!-- rounded_slider_icon_size / 2 -->
<dimen name="rounded_slider_icon_inset">12dp</dimen>
+
+ <dimen name="toast_width">296dp</dimen>
+ <item name="toast_icon_alpha" format="float" type="dimen">1</item>
+ <dimen name="toast_text_size">14sp</dimen>
+ <dimen name="toast_y_offset">48dp</dimen>
+ <dimen name="toast_icon_size">48dp</dimen>
+ <dimen name="toast_bg_radius">28dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index ded8a2e66aea..6196e4a6613a 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -39,4 +39,6 @@
<!-- People Tile flag -->
<bool name="flag_conversations">false</bool>
+
+ <bool name="flag_toast_style">false</bool>
</resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
index 7f04f28198c0..72e4061829fa 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
@@ -32,8 +32,29 @@ public class PipSurfaceTransactionHelper {
private final Matrix mTmpTransform = new Matrix();
private final float[] mTmpFloat9 = new float[9];
private final RectF mTmpSourceRectF = new RectF();
+ private final RectF mTmpDestinationRectF = new RectF();
private final Rect mTmpDestinationRect = new Rect();
+ public void scale(SurfaceControl.Transaction tx, SurfaceControl leash,
+ Rect sourceBounds, Rect destinationBounds) {
+ mTmpSourceRectF.set(sourceBounds);
+ mTmpDestinationRectF.set(destinationBounds);
+ mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
+ tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
+ .setPosition(leash, mTmpDestinationRectF.left, mTmpDestinationRectF.top);
+ }
+
+ public void scale(SurfaceControl.Transaction tx, SurfaceControl leash,
+ Rect sourceBounds, Rect destinationBounds,
+ float degree, float positionX, float positionY) {
+ mTmpSourceRectF.set(sourceBounds);
+ mTmpDestinationRectF.set(destinationBounds);
+ mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
+ mTmpTransform.postRotate(degree, 0, 0);
+ tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
+ .setPosition(leash, positionX, positionY);
+ }
+
public void scaleAndCrop(SurfaceControl.Transaction tx, SurfaceControl leash,
Rect sourceBounds, Rect destinationBounds, Rect insets) {
mTmpSourceRectF.set(sourceBounds);
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 186379af4b1d..f6b239e31e99 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
@@ -43,17 +43,6 @@ public class Task {
public static final String TAG = "Task";
- /* Task callbacks */
- @Deprecated
- public interface TaskCallbacks {
- /* Notifies when a task has been bound */
- void onTaskDataLoaded(Task task, ThumbnailData thumbnailData);
- /* Notifies when a task has been unbound */
- void onTaskDataUnloaded();
- /* Notifies when a task's windowing mode has changed. */
- void onTaskWindowingModeChanged();
- }
-
/**
* The Task Key represents the unique primary key for the task
*/
@@ -209,12 +198,6 @@ public class Task {
public TaskKey key;
/**
- * The temporary sort index in the stack, used when ordering the stack.
- */
- @Deprecated
- public int temporarySortIndexInStack;
-
- /**
* 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.
*/
@@ -229,45 +212,24 @@ public class Task {
public int colorPrimary;
@ViewDebug.ExportedProperty(category="recents")
public int colorBackground;
- @ViewDebug.ExportedProperty(category="recents")
- @Deprecated
- public boolean useLightOnPrimaryColor;
/**
* The task description for this task, only used to reload task icons.
*/
public TaskDescription taskDescription;
- /**
- * The state isLaunchTarget will be set for the correct task upon launching Recents.
- */
- @ViewDebug.ExportedProperty(category="recents")
- @Deprecated
- public boolean isLaunchTarget;
- @ViewDebug.ExportedProperty(category="recents")
- @Deprecated
- public boolean isStackTask;
- @ViewDebug.ExportedProperty(category="recents")
- @Deprecated
- public boolean isSystemApp;
@ViewDebug.ExportedProperty(category="recents")
public boolean isDockable;
- /**
- * Resize mode. See {@link ActivityInfo#resizeMode}.
- */
- @ViewDebug.ExportedProperty(category="recents")
- @Deprecated
- public int resizeMode;
-
@ViewDebug.ExportedProperty(category="recents")
public ComponentName topActivity;
@ViewDebug.ExportedProperty(category="recents")
public boolean isLocked;
- @Deprecated
- private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
+ // Last snapshot data, only used for recent tasks
+ public ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
+ new ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData();
public Task() {
// Do nothing
@@ -289,6 +251,15 @@ public class Task {
this.taskDescription = new TaskDescription();
}
+ public Task(Task other) {
+ this(other.key, other.colorPrimary, other.colorBackground, other.isDockable,
+ other.isLocked, other.taskDescription, other.topActivity);
+ }
+
+ /**
+ * Use {@link Task#Task(Task)}.
+ */
+ @Deprecated
public Task(TaskKey key, int colorPrimary, int colorBackground,
boolean isDockable, boolean isLocked, TaskDescription taskDescription,
ComponentName topActivity) {
@@ -301,103 +272,6 @@ public class Task {
this.topActivity = topActivity;
}
- @Deprecated
- public Task(TaskKey key, Drawable icon, ThumbnailData thumbnail, String title,
- String titleDescription, int colorPrimary, int colorBackground, boolean isLaunchTarget,
- boolean isStackTask, boolean isSystemApp, boolean isDockable,
- TaskDescription taskDescription, int resizeMode, ComponentName topActivity,
- boolean isLocked) {
- this.key = key;
- this.icon = icon;
- this.thumbnail = thumbnail;
- this.title = title;
- this.titleDescription = titleDescription;
- this.colorPrimary = colorPrimary;
- this.colorBackground = colorBackground;
- this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
- Color.WHITE) > 3f;
- this.taskDescription = taskDescription;
- this.isLaunchTarget = isLaunchTarget;
- this.isStackTask = isStackTask;
- this.isSystemApp = isSystemApp;
- this.isDockable = isDockable;
- this.resizeMode = resizeMode;
- this.topActivity = topActivity;
- this.isLocked = isLocked;
- }
-
- /**
- * Copies the metadata from another task, but retains the current callbacks.
- */
- @Deprecated
- public void copyFrom(Task o) {
- this.key = o.key;
- this.icon = o.icon;
- this.thumbnail = o.thumbnail;
- this.title = o.title;
- this.titleDescription = o.titleDescription;
- this.colorPrimary = o.colorPrimary;
- this.colorBackground = o.colorBackground;
- this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
- this.taskDescription = o.taskDescription;
- this.isLaunchTarget = o.isLaunchTarget;
- this.isStackTask = o.isStackTask;
- this.isSystemApp = o.isSystemApp;
- this.isDockable = o.isDockable;
- this.resizeMode = o.resizeMode;
- this.isLocked = o.isLocked;
- this.topActivity = o.topActivity;
- }
-
- /**
- * Add a callback.
- */
- @Deprecated
- public void addCallback(TaskCallbacks cb) {
- if (!mCallbacks.contains(cb)) {
- mCallbacks.add(cb);
- }
- }
-
- /**
- * Remove a callback.
- */
- @Deprecated
- public void removeCallback(TaskCallbacks cb) {
- mCallbacks.remove(cb);
- }
-
- /** Updates the task's windowing mode. */
- @Deprecated
- public void setWindowingMode(int windowingMode) {
- key.setWindowingMode(windowingMode);
- int callbackCount = mCallbacks.size();
- for (int i = 0; i < callbackCount; i++) {
- mCallbacks.get(i).onTaskWindowingModeChanged();
- }
- }
-
- /** Notifies the callback listeners that this task has been loaded */
- @Deprecated
- public void notifyTaskDataLoaded(ThumbnailData thumbnailData, Drawable applicationIcon) {
- this.icon = applicationIcon;
- this.thumbnail = thumbnailData;
- int callbackCount = mCallbacks.size();
- for (int i = 0; i < callbackCount; i++) {
- mCallbacks.get(i).onTaskDataLoaded(this, thumbnailData);
- }
- }
-
- /** Notifies the callback listeners that this task has been unloaded */
- @Deprecated
- public void notifyTaskDataUnloaded(Drawable defaultApplicationIcon) {
- icon = defaultApplicationIcon;
- thumbnail = null;
- for (int i = mCallbacks.size() - 1; i >= 0; i--) {
- mCallbacks.get(i).onTaskDataUnloaded();
- }
- }
-
/**
* Returns the top activity component.
*/
@@ -424,9 +298,6 @@ public class Task {
if (!isDockable) {
writer.print(" dockable=N");
}
- if (isLaunchTarget) {
- writer.print(" launchTarget=Y");
- }
if (isLocked) {
writer.print(" locked=Y");
}
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index caaee5fd3f37..176562799838 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -49,7 +49,6 @@ import android.widget.TextView;
import androidx.annotation.StyleRes;
-import com.android.settingslib.Utils;
import com.android.settingslib.graph.ThemedBatteryDrawable;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher;
@@ -105,11 +104,6 @@ public class BatteryMeterView extends LinearLayout implements
private DualToneHandler mDualToneHandler;
private int mUser;
- /**
- * Whether we should use colors that adapt based on wallpaper/the scrim behind quick settings.
- */
- private boolean mUseWallpaperTextColors;
-
private int mNonAdaptedSingleToneColor;
private int mNonAdaptedForegroundColor;
private int mNonAdaptedBackgroundColor;
@@ -242,31 +236,6 @@ public class BatteryMeterView extends LinearLayout implements
mIsSubscribedForTunerUpdates = false;
}
- /**
- * Sets whether the battery meter view uses the wallpaperTextColor. If we're not using it, we'll
- * revert back to dark-mode-based/tinted colors.
- *
- * @param shouldUseWallpaperTextColor whether we should use wallpaperTextColor for all
- * components
- */
- public void useWallpaperTextColor(boolean shouldUseWallpaperTextColor) {
- if (shouldUseWallpaperTextColor == mUseWallpaperTextColors) {
- return;
- }
-
- mUseWallpaperTextColors = shouldUseWallpaperTextColor;
-
- if (mUseWallpaperTextColors) {
- updateColors(
- Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor),
- Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColorSecondary),
- Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor));
- } else {
- updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor,
- mNonAdaptedSingleToneColor);
- }
- }
-
public void setColorsFromContext(Context context) {
if (context == null) {
return;
@@ -476,13 +445,19 @@ public class BatteryMeterView extends LinearLayout implements
mNonAdaptedForegroundColor = mDualToneHandler.getFillColor(intensity);
mNonAdaptedBackgroundColor = mDualToneHandler.getBackgroundColor(intensity);
- if (!mUseWallpaperTextColors) {
- updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor,
- mNonAdaptedSingleToneColor);
- }
+ updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor,
+ mNonAdaptedSingleToneColor);
}
- private void updateColors(int foregroundColor, int backgroundColor, int singleToneColor) {
+ /**
+ * Sets icon and text colors. This will be overridden by {@code onDarkChanged} events,
+ * if registered.
+ *
+ * @param foregroundColor
+ * @param backgroundColor
+ * @param singleToneColor
+ */
+ public void updateColors(int foregroundColor, int backgroundColor, int singleToneColor) {
mDrawable.setColors(foregroundColor, backgroundColor, singleToneColor);
mTextColor = singleToneColor;
if (mBatteryPercentView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 7776c12f587e..87252ff2b908 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -29,7 +29,6 @@ import android.media.AudioManager;
import android.util.AttributeSet;
import android.util.MathUtils;
import android.util.Pair;
-import android.view.ContextThemeWrapper;
import android.view.DisplayCutout;
import android.view.View;
import android.view.ViewGroup;
@@ -48,7 +47,6 @@ import androidx.lifecycle.LifecycleRegistry;
import com.android.settingslib.Utils;
import com.android.systemui.BatteryMeterView;
-import com.android.systemui.DualToneHandler;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.privacy.OngoingPrivacyChip;
@@ -75,7 +73,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
protected QuickQSPanel mHeaderQsPanel;
private TouchAnimator mStatusIconsAlphaAnimator;
private TouchAnimator mHeaderTextContainerAlphaAnimator;
- private DualToneHandler mDualToneHandler;
private View mSystemIconsView;
private View mQuickQsStatusIcons;
@@ -110,8 +107,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
public QuickStatusBarHeader(Context context, AttributeSet attrs) {
super(context, attrs);
- mDualToneHandler = new DualToneHandler(
- new ContextThemeWrapper(context, R.style.QSHeaderTheme));
}
@Override
@@ -149,10 +144,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
}
void onAttach(TintedIconManager iconManager) {
- int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
- android.R.attr.colorForeground);
- float intensity = getColorIntensity(colorForeground);
- int fillColor = mDualToneHandler.getSingleColor(intensity);
+ int fillColor = Utils.getColorAttrDefaultColor(getContext(),
+ android.R.attr.textColorPrimary);
// Set the correct tint for the status icons so they contrast
iconManager.setTint(fillColor);
@@ -271,14 +264,12 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
int textColor = Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
if (textColor != mTextColorPrimary) {
+ int textColorSecondary = Utils.getColorAttrDefaultColor(mContext,
+ android.R.attr.textColorSecondary);
mTextColorPrimary = textColor;
mClockView.setTextColor(textColor);
-
- float intensity = getColorIntensity(textColor);
- int fillColor = mDualToneHandler.getSingleColor(intensity);
-
- Rect tintArea = new Rect(0, 0, 0, 0);
- mBatteryRemainingIcon.onDarkChanged(tintArea, intensity, fillColor);
+ mBatteryRemainingIcon.updateColors(mTextColorPrimary, textColorSecondary,
+ mTextColorPrimary);
}
updateStatusIconAlphaAnimator();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
index 7d8d86fe691e..eddcf8c1e9ae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
@@ -28,9 +28,7 @@ import android.widget.TextView;
import com.android.settingslib.Utils;
import com.android.settingslib.graph.SignalDrawable;
-import com.android.systemui.DualToneHandler;
import com.android.systemui.R;
-import com.android.systemui.qs.QuickStatusBarHeader;
import java.util.Objects;
@@ -40,9 +38,6 @@ public class QSCarrier extends LinearLayout {
private TextView mCarrierText;
private ImageView mMobileSignal;
private ImageView mMobileRoaming;
- private DualToneHandler mDualToneHandler;
- private ColorStateList mColorForegroundStateList;
- private float mColorForegroundIntensity;
private CellSignalState mLastSignalState;
public QSCarrier(Context context) {
@@ -64,7 +59,6 @@ public class QSCarrier extends LinearLayout {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mDualToneHandler = new DualToneHandler(getContext());
mMobileGroup = findViewById(R.id.mobile_combo);
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) {
mMobileRoaming = findViewById(R.id.mobile_roaming_large);
@@ -74,11 +68,6 @@ public class QSCarrier extends LinearLayout {
mMobileSignal = findViewById(R.id.mobile_signal);
mCarrierText = findViewById(R.id.qs_carrier_text);
mMobileSignal.setImageDrawable(new SignalDrawable(mContext));
-
- int colorForeground = Utils.getColorAttrDefaultColor(mContext,
- android.R.attr.colorForeground);
- mColorForegroundStateList = ColorStateList.valueOf(colorForeground);
- mColorForegroundIntensity = QuickStatusBarHeader.getColorIntensity(colorForeground);
}
/**
@@ -92,8 +81,8 @@ public class QSCarrier extends LinearLayout {
mMobileGroup.setVisibility(state.visible ? View.VISIBLE : View.GONE);
if (state.visible) {
mMobileRoaming.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
- ColorStateList colorStateList = ColorStateList.valueOf(
- mDualToneHandler.getSingleColor(mColorForegroundIntensity));
+ ColorStateList colorStateList = Utils.getColorAttr(mContext,
+ android.R.attr.textColorPrimary);
mMobileRoaming.setImageTintList(colorStateList);
mMobileSignal.setImageTintList(colorStateList);
mMobileSignal.setImageLevel(state.mobileSignalIconId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index 2dd85e9bb98d..778f813b8d07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -74,4 +74,8 @@ public class FeatureFlags {
public boolean isPeopleTileEnabled() {
return mFlagReader.isEnabled(R.bool.flag_conversations);
}
+
+ public boolean isToastStyleEnabled() {
+ return mFlagReader.isEnabled(R.bool.flag_toast_style);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
index e9fcf1aa9598..365cd2a5d20b 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
@@ -20,10 +20,21 @@ import android.animation.Animator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.LayoutInflater;
import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
import android.widget.ToastPresenter;
import com.android.internal.R;
+import com.android.launcher3.icons.IconFactory;
import com.android.systemui.plugins.ToastPlugin;
/**
@@ -35,23 +46,43 @@ public class SystemUIToast implements ToastPlugin.Toast {
final CharSequence mText;
final ToastPlugin.Toast mPluginToast;
- final int mDefaultGravity;
- final int mDefaultY;
+ private final String mPackageName;
+ private final int mUserId;
+ private final LayoutInflater mLayoutInflater;
+ private final boolean mToastStyleEnabled;
+
final int mDefaultX = 0;
final int mDefaultHorizontalMargin = 0;
final int mDefaultVerticalMargin = 0;
- SystemUIToast(Context context, CharSequence text) {
- this(context, text, null);
+ private int mDefaultY;
+ private int mDefaultGravity;
+
+ @NonNull private final View mToastView;
+ @Nullable private final Animator mInAnimator;
+ @Nullable private final Animator mOutAnimator;
+
+ SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text,
+ String packageName, int userId, boolean toastStyleEnabled, int orientation) {
+ this(layoutInflater, context, text, null, packageName, userId,
+ toastStyleEnabled, orientation);
}
- SystemUIToast(Context context, CharSequence text, ToastPlugin.Toast pluginToast) {
+ SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text,
+ ToastPlugin.Toast pluginToast, String packageName, int userId,
+ boolean toastStyleEnabled, int orientation) {
+ mToastStyleEnabled = toastStyleEnabled;
+ mLayoutInflater = layoutInflater;
mContext = context;
mText = text;
mPluginToast = pluginToast;
+ mPackageName = packageName;
+ mUserId = userId;
+ mToastView = inflateToastView();
+ mInAnimator = createInAnimator();
+ mOutAnimator = createOutAnimator();
- mDefaultGravity = context.getResources().getInteger(R.integer.config_toastDefaultGravity);
- mDefaultY = context.getResources().getDimensionPixelSize(R.dimen.toast_y_offset);
+ onOrientationChange(orientation);
}
@Override
@@ -102,28 +133,19 @@ public class SystemUIToast implements ToastPlugin.Toast {
@Override
@NonNull
public View getView() {
- if (isPluginToast() && mPluginToast.getView() != null) {
- return mPluginToast.getView();
- }
- return ToastPresenter.getTextToastView(mContext, mText);
+ return mToastView;
}
@Override
@Nullable
public Animator getInAnimation() {
- if (isPluginToast() && mPluginToast.getInAnimation() != null) {
- return mPluginToast.getInAnimation();
- }
- return null;
+ return mInAnimator;
}
@Override
@Nullable
public Animator getOutAnimation() {
- if (isPluginToast() && mPluginToast.getOutAnimation() != null) {
- return mPluginToast.getOutAnimation();
- }
- return null;
+ return mOutAnimator;
}
/**
@@ -136,4 +158,80 @@ public class SystemUIToast implements ToastPlugin.Toast {
private boolean isPluginToast() {
return mPluginToast != null;
}
+
+ private View inflateToastView() {
+ if (isPluginToast() && mPluginToast.getView() != null) {
+ return mPluginToast.getView();
+ }
+
+ View toastView;
+ if (mToastStyleEnabled) {
+ toastView = mLayoutInflater.inflate(
+ com.android.systemui.R.layout.text_toast, null);
+ ((TextView) toastView.findViewById(com.android.systemui.R.id.text)).setText(mText);
+
+ ((ImageView) toastView.findViewById(com.android.systemui.R.id.icon))
+ .setImageDrawable(getBadgedIcon(mContext, mPackageName, mUserId));
+ } else {
+ toastView = ToastPresenter.getTextToastView(mContext, mText);
+ }
+
+ return toastView;
+ }
+
+ /**
+ * Called on orientation changes to update parameters associated with the toast placement.
+ */
+ public void onOrientationChange(int orientation) {
+ if (mPluginToast != null) {
+ mPluginToast.onOrientationChange(orientation);
+ }
+
+ mDefaultY = mContext.getResources().getDimensionPixelSize(
+ mToastStyleEnabled
+ ? com.android.systemui.R.dimen.toast_y_offset
+ : R.dimen.toast_y_offset);
+ mDefaultGravity =
+ mContext.getResources().getInteger(R.integer.config_toastDefaultGravity);
+ }
+
+ private Animator createInAnimator() {
+ if (isPluginToast() && mPluginToast.getInAnimation() != null) {
+ return mPluginToast.getInAnimation();
+ }
+
+ return mToastStyleEnabled
+ ? ToastDefaultAnimation.Companion.toastIn(getView())
+ : null;
+ }
+
+ private Animator createOutAnimator() {
+ if (isPluginToast() && mPluginToast.getOutAnimation() != null) {
+ return mPluginToast.getOutAnimation();
+ }
+ return mToastStyleEnabled
+ ? ToastDefaultAnimation.Companion.toastOut(getView())
+ : null;
+ }
+
+ /**
+ * Get badged app icon if necessary, similar as used in the Settings UI.
+ * @return The icon to use
+ */
+ public static Drawable getBadgedIcon(@NonNull Context context, String packageName,
+ int userId) {
+ final PackageManager packageManager = context.getPackageManager();
+ try {
+ final ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser(
+ packageName, PackageManager.GET_META_DATA, userId);
+ UserHandle user = UserHandle.getUserHandleForUid(appInfo.uid);
+ IconFactory iconFactory = IconFactory.obtain(context);
+ Bitmap iconBmp = iconFactory.createBadgedIconBitmap(
+ appInfo.loadUnbadgedIcon(packageManager), user, false).icon;
+ return new BitmapDrawable(context.getResources(), iconBmp);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e("SystemUIToast", "could not load icon for package=" + packageName + " e=" + e);
+ return null;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt b/packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
new file mode 100644
index 000000000000..603d69057e5c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.toast
+
+import android.animation.ObjectAnimator
+import android.view.View
+import android.view.animation.LinearInterpolator
+import android.view.animation.PathInterpolator
+import android.animation.AnimatorSet
+
+class ToastDefaultAnimation {
+ /**
+ * sum of the in and out animation durations cannot exceed
+ * [com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_ANIM_BUFFER] to prevent the toast
+ * window from being removed before animations are completed
+ */
+ companion object {
+ // total duration shouldn't exceed NotificationManagerService's delay for "in" animation
+ fun toastIn(view: View): AnimatorSet? {
+ val icon: View? = view.findViewById(com.android.systemui.R.id.icon)
+ val text: View? = view.findViewById(com.android.systemui.R.id.text)
+ if (icon == null || text == null) {
+ return null
+ }
+ val linearInterp = LinearInterpolator()
+ val scaleInterp = PathInterpolator(0f, 0f, 0f, 1f)
+ val sX = ObjectAnimator.ofFloat(view, "scaleX", 0.9f, 1f).apply {
+ interpolator = scaleInterp
+ duration = 333
+ }
+ val sY = ObjectAnimator.ofFloat(view, "scaleY", 0.9f, 1f).apply {
+ interpolator = scaleInterp
+ duration = 333
+ }
+ val vA = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f).apply {
+ interpolator = linearInterp
+ duration = 66
+ }
+ text.alpha = 0f // Set now otherwise won't apply until start delay
+ val tA = ObjectAnimator.ofFloat(text, "alpha", 0f, 1f).apply {
+ interpolator = linearInterp
+ duration = 283
+ startDelay = 50
+ }
+ icon.alpha = 0f // Set now otherwise won't apply until start delay
+ val iA = ObjectAnimator.ofFloat(icon, "alpha", 0f, 1f).apply {
+ interpolator = linearInterp
+ duration = 283
+ startDelay = 50
+ }
+ return AnimatorSet().apply {
+ playTogether(sX, sY, vA, tA, iA)
+ }
+ }
+
+ fun toastOut(view: View): AnimatorSet? {
+ // total duration shouldn't exceed NotificationManagerService's delay for "out" anim
+ val icon: View? = view.findViewById(com.android.systemui.R.id.icon)
+ val text: View? = view.findViewById(com.android.systemui.R.id.text)
+ if (icon == null || text == null) {
+ return null
+ }
+ val linearInterp = LinearInterpolator()
+ val scaleInterp = PathInterpolator(0.3f, 0f, 1f, 1f)
+ val sX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.9f).apply {
+ interpolator = scaleInterp
+ duration = 250
+ }
+ val sY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.9f).apply {
+ interpolator = scaleInterp
+ duration = 250
+ }
+ val vA = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f).apply {
+ interpolator = linearInterp
+ duration = 100
+ startDelay = 150
+ }
+ val tA = ObjectAnimator.ofFloat(text, "alpha", 1f, 0f).apply {
+ interpolator = linearInterp
+ duration = 166
+ }
+ val iA = ObjectAnimator.ofFloat(icon, "alpha", 1f, 0f).apply {
+ interpolator = linearInterp
+ duration = 166
+ }
+ return AnimatorSet().apply {
+ playTogether(sX, sY, vA, tA, iA)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
index d8cb61c6b349..8b782d4b7923 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
@@ -17,6 +17,7 @@
package com.android.systemui.toast;
import android.content.Context;
+import android.view.LayoutInflater;
import androidx.annotation.NonNull;
@@ -26,6 +27,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.ToastPlugin;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.FeatureFlags;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -40,10 +42,18 @@ import javax.inject.Inject;
public class ToastFactory implements Dumpable {
// only one ToastPlugin can be connected at a time.
private ToastPlugin mPlugin;
+ private final LayoutInflater mLayoutInflater;
+ private final boolean mToastStyleEnabled;
@Inject
- public ToastFactory(PluginManager pluginManager, DumpManager dumpManager) {
+ public ToastFactory(
+ LayoutInflater layoutInflater,
+ PluginManager pluginManager,
+ DumpManager dumpManager,
+ FeatureFlags featureFlags) {
+ mLayoutInflater = layoutInflater;
dumpManager.registerDumpable("ToastFactory", this);
+ mToastStyleEnabled = featureFlags.isToastStyleEnabled();
pluginManager.addPluginListener(
new PluginListener<ToastPlugin>() {
@Override
@@ -64,11 +74,13 @@ public class ToastFactory implements Dumpable {
* Create a toast to be shown by ToastUI.
*/
public SystemUIToast createToast(Context context, CharSequence text, String packageName,
- int userId) {
+ int userId, int orientation) {
if (isPluginAvailable()) {
- return new SystemUIToast(context, text, mPlugin.createToast(text, packageName, userId));
+ return new SystemUIToast(mLayoutInflater, context, text, mPlugin.createToast(text,
+ packageName, userId), packageName, userId, mToastStyleEnabled, orientation);
}
- return new SystemUIToast(context, text);
+ return new SystemUIToast(mLayoutInflater, context, text, packageName, userId,
+ mToastStyleEnabled, orientation);
}
private boolean isPluginAvailable() {
@@ -79,5 +91,6 @@ public class ToastFactory implements Dumpable {
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("ToastFactory:");
pw.println(" mAttachedPlugin=" + mPlugin);
+ pw.println(" mToastStyleEnabled=" + mToastStyleEnabled);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt b/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
index 78173cf62a93..51541bd3032e 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
@@ -49,6 +49,15 @@ class ToastLogger @Inject constructor(
})
}
+ fun logOrientationChange(text: String, isPortrait: Boolean) {
+ log(DEBUG, {
+ str1 = text
+ bool1 = isPortrait
+ }, {
+ "Orientation change for toast. msg=\'$str1\' isPortrait=$bool1"
+ })
+ }
+
private inline fun log(
logLevel: LogLevel,
initializer: LogMessage.() -> Unit,
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
index 409d1361223c..92ea1d0e5fbd 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
@@ -16,27 +16,28 @@
package com.android.systemui.toast;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+
import android.animation.Animator;
import android.annotation.MainThread;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.INotificationManager;
import android.app.ITransientNotificationCallback;
import android.content.Context;
+import android.content.res.Configuration;
import android.os.IBinder;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.Log;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
-import android.widget.Toast;
import android.widget.ToastPresenter;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.util.concurrency.DelayableExecutor;
import java.util.Objects;
@@ -58,18 +59,19 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
private final IAccessibilityManager mIAccessibilityManager;
private final AccessibilityManager mAccessibilityManager;
private final ToastFactory mToastFactory;
- private final DelayableExecutor mMainExecutor;
private final ToastLogger mToastLogger;
private SystemUIToast mToast;
@Nullable private ToastPresenter mPresenter;
@Nullable private ITransientNotificationCallback mCallback;
+ private ToastOutAnimatorListener mToastOutAnimatorListener;
+
+ private int mOrientation = ORIENTATION_PORTRAIT;
@Inject
public ToastUI(
Context context,
CommandQueue commandQueue,
ToastFactory toastFactory,
- @Main DelayableExecutor mainExecutor,
ToastLogger toastLogger) {
this(context, commandQueue,
INotificationManager.Stub.asInterface(
@@ -77,21 +79,19 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
IAccessibilityManager.Stub.asInterface(
ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)),
toastFactory,
- mainExecutor,
toastLogger);
}
@VisibleForTesting
ToastUI(Context context, CommandQueue commandQueue, INotificationManager notificationManager,
@Nullable IAccessibilityManager accessibilityManager,
- ToastFactory toastFactory, DelayableExecutor mainExecutor, ToastLogger toastLogger
+ ToastFactory toastFactory, ToastLogger toastLogger
) {
super(context);
mCommandQueue = commandQueue;
mNotificationManager = notificationManager;
mIAccessibilityManager = accessibilityManager;
mToastFactory = toastFactory;
- mMainExecutor = mainExecutor;
mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class);
mToastLogger = toastLogger;
}
@@ -105,36 +105,38 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
@MainThread
public void showToast(int uid, String packageName, IBinder token, CharSequence text,
IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) {
- if (mPresenter != null) {
- hideCurrentToast();
- }
- UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
- Context context = mContext.createContextAsUser(userHandle, 0);
- mToast = mToastFactory.createToast(context, text, packageName, userHandle.getIdentifier());
+ Runnable showToastRunnable = () -> {
+ UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
+ Context context = mContext.createContextAsUser(userHandle, 0);
+ mToast = mToastFactory.createToast(mContext /* sysuiContext */, text, packageName,
+ userHandle.getIdentifier(), mOrientation);
- if (mToast.hasCustomAnimation()) {
if (mToast.getInAnimation() != null) {
mToast.getInAnimation().start();
}
- final Animator hideAnimator = mToast.getOutAnimation();
- if (hideAnimator != null) {
- final long durationMillis = duration == Toast.LENGTH_LONG
- ? TOAST_LONG_TIME : TOAST_SHORT_TIME;
- final long updatedDuration = mAccessibilityManager.getRecommendedTimeoutMillis(
- (int) durationMillis, AccessibilityManager.FLAG_CONTENT_TEXT);
- mMainExecutor.executeDelayed(() -> hideAnimator.start(),
- updatedDuration - hideAnimator.getTotalDuration());
- }
+
+ mCallback = callback;
+ mPresenter = new ToastPresenter(context, mIAccessibilityManager,
+ mNotificationManager, packageName);
+ // Set as trusted overlay so touches can pass through toasts
+ mPresenter.getLayoutParams().setTrustedOverlay();
+ mToastLogger.logOnShowToast(uid, packageName, text.toString(), token.toString());
+ mPresenter.show(mToast.getView(), token, windowToken, duration, mToast.getGravity(),
+ mToast.getXOffset(), mToast.getYOffset(), mToast.getHorizontalMargin(),
+ mToast.getVerticalMargin(), mCallback, mToast.hasCustomAnimation());
+ };
+
+ if (mToastOutAnimatorListener != null) {
+ // if we're currently animating out a toast, show new toast after prev toast is hidden
+ mToastOutAnimatorListener.setShowNextToastRunnable(showToastRunnable);
+ } else if (mPresenter != null) {
+ // if there's a toast already showing that we haven't tried hiding yet, hide it and
+ // then show the next toast after its hidden animation is done
+ hideCurrentToast(showToastRunnable);
+ } else {
+ // else, show this next toast immediately
+ showToastRunnable.run();
}
- mCallback = callback;
- mPresenter = new ToastPresenter(context, mIAccessibilityManager, mNotificationManager,
- packageName);
- // Set as trusted overlay so touches can pass through toasts
- mPresenter.getLayoutParams().setTrustedOverlay();
- mToastLogger.logOnShowToast(uid, packageName, text.toString(), token.toString());
- mPresenter.show(mToast.getView(), token, windowToken, duration, mToast.getGravity(),
- mToast.getXOffset(), mToast.getYOffset(), mToast.getHorizontalMargin(),
- mToast.getVerticalMargin(), mCallback, mToast.hasCustomAnimation());
}
@Override
@@ -146,12 +148,88 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
return;
}
mToastLogger.logOnHideToast(packageName, token.toString());
- hideCurrentToast();
+ hideCurrentToast(null);
}
@MainThread
- private void hideCurrentToast() {
- mPresenter.hide(mCallback);
+ private void hideCurrentToast(Runnable runnable) {
+ if (mToast.getOutAnimation() != null) {
+ Animator animator = mToast.getOutAnimation();
+ mToastOutAnimatorListener = new ToastOutAnimatorListener(mPresenter, mCallback,
+ runnable);
+ animator.addListener(mToastOutAnimatorListener);
+ animator.start();
+ } else {
+ mPresenter.hide(mCallback);
+ if (runnable != null) {
+ runnable.run();
+ }
+ }
+ mToast = null;
mPresenter = null;
+ mCallback = null;
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ if (newConfig.orientation != mOrientation) {
+ mOrientation = newConfig.orientation;
+ if (mToast != null) {
+ mToastLogger.logOrientationChange(mToast.mText.toString(),
+ mOrientation == ORIENTATION_PORTRAIT);
+ mToast.onOrientationChange(mOrientation);
+ mPresenter.updateLayoutParams(
+ mToast.getXOffset(),
+ mToast.getYOffset(),
+ mToast.getHorizontalMargin(),
+ mToast.getVerticalMargin(),
+ mToast.getGravity());
+ }
+ }
+ }
+
+ /**
+ * Once the out animation for a toast is finished, start showing the next toast.
+ */
+ class ToastOutAnimatorListener implements Animator.AnimatorListener {
+ final ToastPresenter mPrevPresenter;
+ final ITransientNotificationCallback mPrevCallback;
+ @Nullable Runnable mShowNextToastRunnable;
+
+ ToastOutAnimatorListener(
+ @NonNull ToastPresenter presenter,
+ @NonNull ITransientNotificationCallback callback,
+ @Nullable Runnable runnable) {
+ mPrevPresenter = presenter;
+ mPrevCallback = callback;
+ mShowNextToastRunnable = runnable;
+ }
+
+ void setShowNextToastRunnable(Runnable runnable) {
+ mShowNextToastRunnable = runnable;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mPrevPresenter.hide(mPrevCallback);
+ if (mShowNextToastRunnable != null) {
+ mShowNextToastRunnable.run();
+ }
+ mToastOutAnimatorListener = null;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ onAnimationEnd(animation);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
index c743fd07c492..365c62cddbdf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
@@ -57,8 +57,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.statusbar.FeatureFlags;
import org.junit.Before;
import org.junit.Test;
@@ -88,7 +87,6 @@ public class ToastUITest extends SysuiTestCase {
private static final String TEXT = "Hello World";
private static final int MESSAGE_RES_ID = R.id.message;
- private FakeExecutor mFakeDelayableExecutor = new FakeExecutor(new FakeSystemClock());
private Context mContextSpy;
private ToastUI mToastUI;
@Mock private LayoutInflater mLayoutInflater;
@@ -99,6 +97,7 @@ public class ToastUITest extends SysuiTestCase {
@Mock private PluginManager mPluginManager;
@Mock private DumpManager mDumpManager;
@Mock private ToastLogger mToastLogger;
+ @Mock private FeatureFlags mFeatureFlags;
@Mock private ITransientNotificationCallback mCallback;
@Captor private ArgumentCaptor<View> mViewCaptor;
@@ -107,12 +106,9 @@ public class ToastUITest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
-
- // This is because inflate will result in WindowManager (WM) calls, which will fail since we
- // are mocking it, so we mock LayoutInflater with the view obtained before mocking WM.
- View view = ToastPresenter.getTextToastView(mContext, TEXT);
- when(mLayoutInflater.inflate(eq(TEXT_TOAST_LAYOUT), any())).thenReturn(view);
- mContext.addMockSystemService(LayoutInflater.class, mLayoutInflater);
+ when(mLayoutInflater.inflate(eq(TEXT_TOAST_LAYOUT), any())).thenReturn(
+ ToastPresenter.getTextToastView(mContext, TEXT));
+ when(mFeatureFlags.isToastStyleEnabled()).thenReturn(false);
mContext.addMockSystemService(WindowManager.class, mWindowManager);
mContextSpy = spy(mContext);
@@ -120,8 +116,8 @@ public class ToastUITest extends SysuiTestCase {
doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt());
mToastUI = new ToastUI(mContextSpy, mCommandQueue, mNotificationManager,
- mAccessibilityManager, new ToastFactory(mPluginManager, mDumpManager),
- mFakeDelayableExecutor, mToastLogger);
+ mAccessibilityManager, new ToastFactory(mLayoutInflater, mPluginManager,
+ mDumpManager, mFeatureFlags), mToastLogger);
}
@Test
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 7e65434b8189..8b6fabd7faff 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -967,6 +967,12 @@ public final class BroadcastQueue {
}
}
+ static String broadcastDescription(BroadcastRecord r, ComponentName component) {
+ return r.intent.toString()
+ + " from " + r.callerPackage + " (pid=" + r.callingPid
+ + ", uid=" + r.callingUid + ") to " + component.flattenToShortString();
+ }
+
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
@@ -1349,14 +1355,18 @@ public final class BroadcastQueue {
< brOptions.getMinManifestReceiverApiLevel() ||
info.activityInfo.applicationInfo.targetSdkVersion
> brOptions.getMaxManifestReceiverApiLevel())) {
+ Slog.w(TAG, "Target SDK mismatch: receiver " + info.activityInfo
+ + " targets " + info.activityInfo.applicationInfo.targetSdkVersion
+ + " but delivery restricted to ["
+ + brOptions.getMinManifestReceiverApiLevel() + ", "
+ + brOptions.getMaxManifestReceiverApiLevel()
+ + "] broadcasting " + broadcastDescription(r, component));
skip = true;
}
if (!skip && !mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
component.getPackageName(), info.activityInfo.applicationInfo.uid)) {
Slog.w(TAG, "Association not allowed: broadcasting "
- + r.intent.toString()
- + " from " + r.callerPackage + " (pid=" + r.callingPid
- + ", uid=" + r.callingUid + ") to " + component.flattenToShortString());
+ + broadcastDescription(r, component));
skip = true;
}
if (!skip) {
@@ -1364,9 +1374,7 @@ public final class BroadcastQueue {
r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid);
if (skip) {
Slog.w(TAG, "Firewall blocked: broadcasting "
- + r.intent.toString()
- + " from " + r.callerPackage + " (pid=" + r.callingPid
- + ", uid=" + r.callingUid + ") to " + component.flattenToShortString());
+ + broadcastDescription(r, component));
}
}
int perm = mService.checkComponentPermission(info.activityInfo.permission,
@@ -1375,18 +1383,12 @@ public final class BroadcastQueue {
if (!skip && perm != PackageManager.PERMISSION_GRANTED) {
if (!info.activityInfo.exported) {
Slog.w(TAG, "Permission Denial: broadcasting "
- + r.intent.toString()
- + " from " + r.callerPackage + " (pid=" + r.callingPid
- + ", uid=" + r.callingUid + ")"
- + " is not exported from uid " + info.activityInfo.applicationInfo.uid
- + " due to receiver " + component.flattenToShortString());
+ + broadcastDescription(r, component)
+ + " is not exported from uid " + info.activityInfo.applicationInfo.uid);
} else {
Slog.w(TAG, "Permission Denial: broadcasting "
- + r.intent.toString()
- + " from " + r.callerPackage + " (pid=" + r.callingPid
- + ", uid=" + r.callingUid + ")"
- + " requires " + info.activityInfo.permission
- + " due to receiver " + component.flattenToShortString());
+ + broadcastDescription(r, component)
+ + " requires " + info.activityInfo.permission);
}
skip = true;
} else if (!skip && info.activityInfo.permission != null) {
@@ -1396,13 +1398,9 @@ public final class BroadcastQueue {
"Broadcast delivered to " + info.activityInfo.name)
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: broadcasting "
- + r.intent.toString()
- + " from " + r.callerPackage + " (pid="
- + r.callingPid + ", uid=" + r.callingUid + ")"
+ + broadcastDescription(r, component)
+ " requires appop " + AppOpsManager.permissionToOp(
- info.activityInfo.permission)
- + " due to registered receiver "
- + component.flattenToShortString());
+ info.activityInfo.permission));
skip = true;
}
}
@@ -1520,7 +1518,7 @@ public final class BroadcastQueue {
+ info.activityInfo.packageName, e);
}
if (!isAvailable) {
- if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
+ Slog.w(TAG_BROADCAST,
"Skipping delivery to " + info.activityInfo.packageName + " / "
+ info.activityInfo.applicationInfo.uid
+ " : package no longer available");
@@ -1536,6 +1534,9 @@ public final class BroadcastQueue {
if (!requestStartTargetPermissionsReviewIfNeededLocked(r,
info.activityInfo.packageName, UserHandle.getUserId(
info.activityInfo.applicationInfo.uid))) {
+ Slog.w(TAG_BROADCAST,
+ "Skipping delivery: permission review required for "
+ + broadcastDescription(r, component));
skip = true;
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1a4c8b7d6571..00ae30e2aa0e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -5246,12 +5246,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
imeTracing.startTrace(null);
});
}
- }
- doDump(fd, pw, args, asProto);
- }
- private void doDump(FileDescriptor fd, PrintWriter pw, String[] args, boolean useProto) {
- if (useProto) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
dumpDebug(proto, InputMethodManagerServiceTraceProto.INPUT_METHOD_MANAGER_SERVICE);
proto.flush();
diff --git a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
index a1e18bd5a6bd..5bd3f6455ecb 100644
--- a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
+++ b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
@@ -120,6 +120,7 @@ public class ResumeOnRebootServiceProvider {
if (mServiceConnection != null) {
mContext.unbindService(mServiceConnection);
}
+ mBinder = null;
}
/** Bind to the service */
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4c3dfbff3f87..5703ffec21a0 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -110,6 +110,8 @@ import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
+import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_ANIM_BUFFER;
+import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
@@ -284,7 +286,6 @@ import com.android.server.notification.toast.CustomToastRecord;
import com.android.server.notification.toast.TextToastRecord;
import com.android.server.notification.toast.ToastRecord;
import com.android.server.pm.PackageManagerService;
-import com.android.server.policy.PhoneWindowManager;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.utils.quota.MultiRateLimiter;
@@ -358,7 +359,7 @@ public class NotificationManagerService extends SystemService {
private static final int MESSAGE_RECONSIDER_RANKING = 1000;
private static final int MESSAGE_RANKING_SORT = 1001;
- static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
+ static final int LONG_DELAY = TOAST_WINDOW_TIMEOUT - TOAST_WINDOW_ANIM_BUFFER; // 3.5 seconds
static final int SHORT_DELAY = 2000; // 2 seconds
// 1 second past the ANR timeout.
@@ -3056,7 +3057,7 @@ public class NotificationManagerService extends SystemService {
// If the callback fails, this will remove it from the list, so don't
// assume that it's valid after this.
if (index == 0) {
- showNextToastLocked();
+ showNextToastLocked(false);
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -7392,7 +7393,7 @@ public class NotificationManagerService extends SystemService {
}
@GuardedBy("mToastQueue")
- void showNextToastLocked() {
+ void showNextToastLocked(boolean lastToastWasTextRecord) {
if (mIsCurrentToastShown) {
return; // Don't show the same toast twice.
}
@@ -7406,7 +7407,7 @@ public class NotificationManagerService extends SystemService {
mToastRateLimiter.isWithinQuota(userId, record.pkg, TOAST_QUOTA_TAG);
if (tryShowToast(record, rateLimitingEnabled, isWithinQuota)) {
- scheduleDurationReachedLocked(record);
+ scheduleDurationReachedLocked(record, lastToastWasTextRecord);
mIsCurrentToastShown = true;
if (rateLimitingEnabled) {
mToastRateLimiter.noteEvent(userId, record.pkg, TOAST_QUOTA_TAG);
@@ -7477,7 +7478,7 @@ public class NotificationManagerService extends SystemService {
// Show the next one. If the callback fails, this will remove
// it from the list, so don't assume that the list hasn't changed
// after this point.
- showNextToastLocked();
+ showNextToastLocked(lastToast instanceof TextToastRecord);
}
}
@@ -7491,7 +7492,7 @@ public class NotificationManagerService extends SystemService {
}
@GuardedBy("mToastQueue")
- private void scheduleDurationReachedLocked(ToastRecord r)
+ private void scheduleDurationReachedLocked(ToastRecord r, boolean lastToastWasTextRecord)
{
mHandler.removeCallbacksAndMessages(r);
Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
@@ -7501,6 +7502,14 @@ public class NotificationManagerService extends SystemService {
// preference.
delay = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
AccessibilityManager.FLAG_CONTENT_TEXT);
+
+ if (lastToastWasTextRecord) {
+ delay += 250; // delay to account for previous toast's "out" animation
+ }
+ if (r instanceof TextToastRecord) {
+ delay += 333; // delay to account for this toast's "in" animation
+ }
+
mHandler.sendMessageDelayed(m, delay);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index bc819617332d..6a441f1830d1 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -346,8 +346,21 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
- /** Amount of time (in milliseconds) a toast window can be shown. */
- public static final int TOAST_WINDOW_TIMEOUT = 3500; // 3.5 seconds
+ /**
+ * Extra time for additional SystemUI animations.
+ * <p>Since legacy apps can add Toast windows directly instead of using Toast APIs,
+ * {@link DisplayPolicy} ensures that the window manager removes toast windows after
+ * TOAST_WINDOW_TIMEOUT. We increase this timeout by TOAST_WINDOW_ANIM_BUFFER to account for
+ * SystemUI's in/out toast animations, so that the toast text is still shown for a minimum
+ * of 3.5 seconds and the animations are finished before window manager removes the window.
+ */
+ public static final int TOAST_WINDOW_ANIM_BUFFER = 600;
+
+ /**
+ * Amount of time (in milliseconds) a toast window can be shown before it's automatically
+ * removed by window manager.
+ */
+ public static final int TOAST_WINDOW_TIMEOUT = 3500 + TOAST_WINDOW_ANIM_BUFFER;
/**
* Lock protecting internal state. Must not call out into window
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 6e8110e9c36e..d81181d46417 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -58,6 +58,8 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
@@ -1886,6 +1888,7 @@ class RecentTasks {
// Fill in some deprecated values.
rti.id = rti.isRunning ? rti.taskId : INVALID_TASK_ID;
rti.persistentId = rti.taskId;
+ rti.lastSnapshotData.set(tr.mLastTaskSnapshotData);
// Fill in organized child task info for the task created by organizer.
if (tr.mCreatedByOrganizer) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9bbbbe0a8535..9c8a997ec098 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -158,6 +158,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData;
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
@@ -293,6 +294,9 @@ class Task extends WindowContainer<WindowContainer> {
private static final String ATTR_MIN_HEIGHT = "min_height";
private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity";
+ private static final String ATTR_LAST_SNAPSHOT_TASK_SIZE = "last_snapshot_task_size";
+ private static final String ATTR_LAST_SNAPSHOT_CONTENT_INSETS = "last_snapshot_content_insets";
+ private static final String ATTR_LAST_SNAPSHOT_BUFFER_SIZE = "last_snapshot_buffer_size";
// Set to false to disable the preview that is shown while a new activity
// is being started.
@@ -540,6 +544,10 @@ class Task extends WindowContainer<WindowContainer> {
// NOTE: This value needs to be persisted with each task
private TaskDescription mTaskDescription;
+ // Information about the last snapshot that should be persisted with the task to allow SystemUI
+ // to layout without loading all the task snapshots
+ final PersistedTaskSnapshotData mLastTaskSnapshotData;
+
// If set to true, the task will report that it is not in the floating
// state regardless of it's root task affiliation. As the floating state drives
// production of content insets this can be used to preserve them across
@@ -613,8 +621,6 @@ class Task extends WindowContainer<WindowContainer> {
SurfaceControl.Transaction mMainWindowSizeChangeTransaction;
Task mMainWindowSizeChangeTask;
- Rect mPreAnimationBounds = new Rect();
-
private final AnimatingActivityRegistry mAnimatingActivityRegistry =
new AnimatingActivityRegistry();
@@ -839,13 +845,13 @@ class Task extends WindowContainer<WindowContainer> {
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, int _effectiveUid,
String _lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity,
- TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
- int nextTaskId, int callingUid, String callingPackage,
- @Nullable String callingFeatureId, int resizeMode, boolean supportsPictureInPicture,
- boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight,
- ActivityInfo info, IVoiceInteractionSession _voiceSession,
- IVoiceInteractor _voiceInteractor, boolean _createdByOrganizer,
- IBinder _launchCookie, boolean _deferTaskAppear) {
+ TaskDescription _lastTaskDescription, PersistedTaskSnapshotData _lastSnapshotData,
+ int taskAffiliation, int prevTaskId, int nextTaskId, int callingUid,
+ String callingPackage, @Nullable String callingFeatureId, int resizeMode,
+ boolean supportsPictureInPicture, boolean _realActivitySuspended,
+ boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
+ IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
+ boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear) {
super(atmService.mWindowManager);
mAtmService = atmService;
@@ -855,7 +861,12 @@ class Task extends WindowContainer<WindowContainer> {
mUserId = _userId;
mResizeMode = resizeMode;
mSupportsPictureInPicture = supportsPictureInPicture;
- mTaskDescription = _lastTaskDescription;
+ mTaskDescription = _lastTaskDescription != null
+ ? _lastTaskDescription
+ : new TaskDescription();
+ mLastTaskSnapshotData = _lastSnapshotData != null
+ ? _lastSnapshotData
+ : new PersistedTaskSnapshotData();
// Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
setOrientation(SCREEN_ORIENTATION_UNSET);
mRemoteToken = new RemoteToken(this);
@@ -3899,6 +3910,7 @@ class Task extends WindowContainer<WindowContainer> {
}
void onSnapshotChanged(TaskSnapshot snapshot) {
+ mLastTaskSnapshotData.set(snapshot);
mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(
mTaskId, snapshot);
}
@@ -4157,7 +4169,6 @@ class Task extends WindowContainer<WindowContainer> {
void fillTaskInfo(TaskInfo info, boolean stripExtras) {
getNumRunningActivities(mReuseActivitiesReport);
info.userId = isLeafTask() ? mUserId : mCurrentUser;
- info.stackId = getRootTaskId();
info.taskId = mTaskId;
info.displayId = getDisplayId();
info.isRunning = getTopNonFinishingActivity() != null;
@@ -4707,6 +4718,19 @@ class Task extends WindowContainer<WindowContainer> {
out.attributeInt(null, ATTR_MIN_HEIGHT, mMinHeight);
out.attributeInt(null, ATTR_PERSIST_TASK_VERSION, PERSIST_TASK_VERSION);
+ if (mLastTaskSnapshotData.taskSize != null) {
+ out.attribute(null, ATTR_LAST_SNAPSHOT_TASK_SIZE,
+ mLastTaskSnapshotData.taskSize.flattenToString());
+ }
+ if (mLastTaskSnapshotData.contentInsets != null) {
+ out.attribute(null, ATTR_LAST_SNAPSHOT_CONTENT_INSETS,
+ mLastTaskSnapshotData.contentInsets.flattenToString());
+ }
+ if (mLastTaskSnapshotData.bufferSize != null) {
+ out.attribute(null, ATTR_LAST_SNAPSHOT_BUFFER_SIZE,
+ mLastTaskSnapshotData.bufferSize.flattenToString());
+ }
+
if (affinityIntent != null) {
out.startTag(null, TAG_AFFINITYINTENT);
affinityIntent.saveToXml(out);
@@ -4774,6 +4798,7 @@ class Task extends WindowContainer<WindowContainer> {
int taskId = INVALID_TASK_ID;
final int outerDepth = in.getDepth();
TaskDescription taskDescription = new TaskDescription();
+ PersistedTaskSnapshotData lastSnapshotData = new PersistedTaskSnapshotData();
int taskAffiliation = INVALID_TASK_ID;
int prevTaskId = INVALID_TASK_ID;
int nextTaskId = INVALID_TASK_ID;
@@ -4883,6 +4908,15 @@ class Task extends WindowContainer<WindowContainer> {
case ATTR_PERSIST_TASK_VERSION:
persistTaskVersion = Integer.parseInt(attrValue);
break;
+ case ATTR_LAST_SNAPSHOT_TASK_SIZE:
+ lastSnapshotData.taskSize = Point.unflattenFromString(attrValue);
+ break;
+ case ATTR_LAST_SNAPSHOT_CONTENT_INSETS:
+ lastSnapshotData.contentInsets = Rect.unflattenFromString(attrValue);
+ break;
+ case ATTR_LAST_SNAPSHOT_BUFFER_SIZE:
+ lastSnapshotData.bufferSize = Point.unflattenFromString(attrValue);
+ break;
default:
if (!attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
Slog.w(TAG, "Task: Unknown attribute=" + attrName);
@@ -4977,6 +5011,7 @@ class Task extends WindowContainer<WindowContainer> {
.setLastTimeMoved(lastTimeOnTop)
.setNeverRelinquishIdentity(neverRelinquishIdentity)
.setLastTaskDescription(taskDescription)
+ .setLastSnapshotData(lastSnapshotData)
.setTaskAffiliation(taskAffiliation)
.setPrevAffiliateTaskId(prevTaskId)
.setNextAffiliateTaskId(nextTaskId)
@@ -7904,6 +7939,7 @@ class Task extends WindowContainer<WindowContainer> {
private long mLastTimeMoved;
private boolean mNeverRelinquishIdentity;
private TaskDescription mLastTaskDescription;
+ private PersistedTaskSnapshotData mLastSnapshotData;
private int mTaskAffiliation;
private int mPrevAffiliateTaskId = INVALID_TASK_ID;
private int mNextAffiliateTaskId = INVALID_TASK_ID;
@@ -8104,6 +8140,11 @@ class Task extends WindowContainer<WindowContainer> {
return this;
}
+ private Builder setLastSnapshotData(PersistedTaskSnapshotData lastSnapshotData) {
+ mLastSnapshotData = lastSnapshotData;
+ return this;
+ }
+
private Builder setOrigActivity(ComponentName origActivity) {
mOrigActivity = origActivity;
return this;
@@ -8217,9 +8258,6 @@ class Task extends WindowContainer<WindowContainer> {
mCallingPackage = mActivityInfo.packageName;
mResizeMode = mActivityInfo.resizeMode;
mSupportsPictureInPicture = mActivityInfo.supportsPictureInPicture();
- if (mLastTaskDescription == null) {
- mLastTaskDescription = new TaskDescription();
- }
final Task task = buildInner();
task.mHasBeenVisible = mHasBeenVisible;
@@ -8253,9 +8291,9 @@ class Task extends WindowContainer<WindowContainer> {
return new Task(mAtmService, mTaskId, mIntent, mAffinityIntent, mAffinity,
mRootAffinity, mRealActivity, mOrigActivity, mRootWasReset, mAutoRemoveRecents,
mAskedCompatMode, mUserId, mEffectiveUid, mLastDescription, mLastTimeMoved,
- mNeverRelinquishIdentity, mLastTaskDescription, mTaskAffiliation,
- mPrevAffiliateTaskId, mNextAffiliateTaskId, mCallingUid, mCallingPackage,
- mCallingFeatureId, mResizeMode, mSupportsPictureInPicture,
+ mNeverRelinquishIdentity, mLastTaskDescription, mLastSnapshotData,
+ mTaskAffiliation, mPrevAffiliateTaskId, mNextAffiliateTaskId, mCallingUid,
+ mCallingPackage, mCallingFeatureId, mResizeMode, mSupportsPictureInPicture,
mRealActivitySuspended, mUserSetupComplete, mMinWidth, mMinHeight,
mActivityInfo, mVoiceSession, mVoiceInteractor, mCreatedByOrganizer,
mLaunchCookie, mDeferTaskAppear);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index bd109922cb42..07eb7bf8f9a0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -16328,8 +16328,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
setTimeAndTimezone(provisioningParams.getTimeZone(), provisioningParams.getLocalTime());
setLocale(provisioningParams.getLocale());
+ final int deviceOwnerUserId = mInjector.userManagerIsHeadlessSystemUserMode()
+ ? UserHandle.USER_SYSTEM : caller.getUserId();
if (!removeNonRequiredAppsForManagedDevice(
- caller.getUserId(),
+ deviceOwnerUserId,
provisioningParams.isLeaveAllSystemAppsEnabled(),
deviceAdmin)) {
throw new ServiceSpecificException(
@@ -16337,15 +16339,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
"PackageManager failed to remove non required apps.");
}
+
if (!setActiveAdminAndDeviceOwner(
- caller.getUserId(), deviceAdmin, provisioningParams.getOwnerName())) {
+ deviceOwnerUserId, deviceAdmin, provisioningParams.getOwnerName())) {
throw new ServiceSpecificException(
PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED,
"Failed to set device owner.");
}
disallowAddUser();
- setAdminCanGrantSensorsPermissionForUserUnchecked(caller.getUserId(),
+ setAdminCanGrantSensorsPermissionForUserUnchecked(deviceOwnerUserId,
provisioningParams.canDeviceOwnerGrantSensorsPermissions());
} catch (Exception e) {
DevicePolicyEventLogger
@@ -16388,30 +16391,42 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
private boolean removeNonRequiredAppsForManagedDevice(
- int userId, boolean leaveAllSystemAppsEnabled, ComponentName admin) {
+ @UserIdInt int userId, boolean leaveAllSystemAppsEnabled, ComponentName admin) {
Set<String> packagesToDelete = leaveAllSystemAppsEnabled
? Collections.emptySet()
: mOverlayPackagesProvider.getNonRequiredApps(
admin, userId, ACTION_PROVISION_MANAGED_DEVICE);
+
+ removeNonInstalledPackages(packagesToDelete, userId);
if (packagesToDelete.isEmpty()) {
+ Slog.i(LOG_TAG, "No packages to delete on user " + userId);
return true;
}
+
NonRequiredPackageDeleteObserver packageDeleteObserver =
new NonRequiredPackageDeleteObserver(packagesToDelete.size());
for (String packageName : packagesToDelete) {
- if (isPackageInstalledForUser(packageName, userId)) {
- Slog.i(LOG_TAG, "Deleting package [" + packageName + "] as user " + userId);
- mContext.getPackageManager().deletePackageAsUser(
- packageName,
- packageDeleteObserver,
- PackageManager.DELETE_SYSTEM_APP,
- userId);
- }
+ Slog.i(LOG_TAG, "Deleting package [" + packageName + "] as user " + userId);
+ mContext.getPackageManager().deletePackageAsUser(
+ packageName,
+ packageDeleteObserver,
+ PackageManager.DELETE_SYSTEM_APP,
+ userId);
}
Slog.i(LOG_TAG, "Waiting for non required apps to be deleted");
return packageDeleteObserver.awaitPackagesDeletion();
}
+ private void removeNonInstalledPackages(Set<String> packages, @UserIdInt int userId) {
+ final Set<String> toBeRemoved = new HashSet<>();
+ for (String packageName : packages) {
+ if (!isPackageInstalledForUser(packageName, userId)) {
+ toBeRemoved.add(packageName);
+ }
+ }
+ packages.removeAll(toBeRemoved);
+ }
+
private void disallowAddUser() {
if (mInjector.userManagerIsHeadlessSystemUserMode()) {
Slog.i(LOG_TAG, "Not setting DISALLOW_ADD_USER on headless system user mode.");
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 98c3b99124ee..97e75828ed91 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -525,8 +525,7 @@ public final class SystemServer implements Dumpable {
String filename = "/data/system/heapdump/fdtrack-" + date + ".hprof";
Debug.dumpHprofData(filename);
} catch (IOException ex) {
- Slog.e("System", "Failed to dump fdtrack hprof");
- ex.printStackTrace();
+ Slog.e("System", "Failed to dump fdtrack hprof", ex);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 21fd04ee3ae9..925b6f9601be 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -29,6 +29,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -59,6 +60,10 @@ import android.app.ActivityTaskManager;
import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
+import android.graphics.ColorSpace;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -66,6 +71,8 @@ import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
import android.util.SparseBooleanArray;
+import android.view.Surface;
+import android.window.TaskSnapshot;
import androidx.test.filters.MediumTest;
@@ -446,12 +453,8 @@ public class RecentTasksTest extends WindowTestsBase {
doReturn(false).when(child2).isOrganized();
mRecentTasks.add(root);
- doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
- doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
- final List<RecentTaskInfo> infos = mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
- true /* getTasksAllowed */, TEST_USER_0_ID, 0 /* callingUid */).getList();
-
// Make sure only organized child will be appended.
+ final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
final List<RecentTaskInfo> childrenTaskInfos = infos.get(0).childrenTaskInfos;
assertEquals(childrenTaskInfos.size(), 1);
assertEquals(childrenTaskInfos.get(0).taskId, child1.mTaskId);
@@ -1051,9 +1054,6 @@ public class RecentTasksTest extends WindowTestsBase {
@Test
public void testTaskInfo_expectNoExtras() {
- doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
- doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
-
final Bundle data = new Bundle();
data.putInt("key", 100);
final Task task1 = createTaskBuilder(".Task").build();
@@ -1063,8 +1063,7 @@ public class RecentTasksTest extends WindowTestsBase {
.build();
mRecentTasks.add(r1.getTask());
- final List<RecentTaskInfo> infos = mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
- true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList();
+ final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
assertTrue(infos.size() == 1);
for (int i = 0; i < infos.size(); i++) {
final Bundle extras = infos.get(i).baseIntent.getExtras();
@@ -1072,6 +1071,60 @@ public class RecentTasksTest extends WindowTestsBase {
}
}
+ @Test
+ public void testLastSnapshotData_snapshotSaved() {
+ final TaskSnapshot snapshot = createSnapshot(new Point(100, 100), new Point(80, 80));
+ final Task task1 = createTaskBuilder(".Task").build();
+ task1.onSnapshotChanged(snapshot);
+
+ mRecentTasks.add(task1);
+ final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
+ final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
+ infos.get(0).lastSnapshotData;
+ assertTrue(lastSnapshotData.taskSize.equals(100, 100));
+ assertTrue(lastSnapshotData.bufferSize.equals(80, 80));
+ }
+
+ @Test
+ public void testLastSnapshotData_noBuffer() {
+ final Task task1 = createTaskBuilder(".Task").build();
+ final TaskSnapshot snapshot = createSnapshot(new Point(100, 100), null);
+ task1.onSnapshotChanged(snapshot);
+
+ mRecentTasks.add(task1);
+ final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
+ final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
+ infos.get(0).lastSnapshotData;
+ assertTrue(lastSnapshotData.taskSize.equals(100, 100));
+ assertNull(lastSnapshotData.bufferSize);
+ }
+
+ @Test
+ public void testLastSnapshotData_notSet() {
+ final Task task1 = createTaskBuilder(".Task").build();
+
+ mRecentTasks.add(task1);
+ final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
+ final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
+ infos.get(0).lastSnapshotData;
+ assertNull(lastSnapshotData.taskSize);
+ assertNull(lastSnapshotData.bufferSize);
+ }
+
+ private TaskSnapshot createSnapshot(Point taskSize, Point bufferSize) {
+ HardwareBuffer buffer = null;
+ if (bufferSize != null) {
+ buffer = mock(HardwareBuffer.class);
+ doReturn(bufferSize.x).when(buffer).getWidth();
+ doReturn(bufferSize.y).when(buffer).getHeight();
+ }
+ return new TaskSnapshot(1, new ComponentName("", ""), buffer,
+ ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
+ Surface.ROTATION_0, taskSize, new Rect() /* insets */, false /* isLowResolution */,
+ true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, 0 /* mSystemUiVisibility */,
+ false /* isTranslucent */, false /* hasImeSurface */);
+ }
+
/**
* Ensures that the raw recent tasks list is in the provided order. Note that the expected tasks
* should be ordered from least to most recent.
@@ -1084,15 +1137,19 @@ public class RecentTasksTest extends WindowTestsBase {
}
}
+ private List<RecentTaskInfo> getRecentTasks(int flags) {
+ doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
+ doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
+ return mRecentTasks.getRecentTasks(MAX_VALUE, flags, true /* getTasksAllowed */,
+ TEST_USER_0_ID, 0 /* callingUid */).getList();
+ }
+
/**
* Ensures that the recent tasks list is in the provided order. Note that the expected tasks
* should be ordered from least to most recent.
*/
private void assertGetRecentTasksOrder(int getRecentTaskFlags, Task... expectedTasks) {
- doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
- doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
- List<RecentTaskInfo> infos = mRecentTasks.getRecentTasks(MAX_VALUE, getRecentTaskFlags,
- true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList();
+ List<RecentTaskInfo> infos = getRecentTasks(getRecentTaskFlags);
assertTrue(expectedTasks.length == infos.size());
for (int i = 0; i < infos.size(); i++) {
assertTrue(expectedTasks[i].mTaskId == infos.get(i).taskId);