Merge "Device always wakes up when the bouncer shows" into tm-qpr-dev
diff --git a/core/java/android/view/InsetsFrameProvider.java b/core/java/android/view/InsetsFrameProvider.java
index 9e66f54..eb8687c 100644
--- a/core/java/android/view/InsetsFrameProvider.java
+++ b/core/java/android/view/InsetsFrameProvider.java
@@ -16,10 +16,14 @@
package android.view;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
+
import android.graphics.Insets;
+import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Arrays;
import java.util.Objects;
/**
@@ -52,7 +56,9 @@
public static final int SOURCE_FRAME = 2;
private static final int HAS_INSETS_SIZE = 1;
- private static final int HAS_IME_INSETS_SIZE = 2;
+ private static final int HAS_INSETS_SIZE_OVERRIDE = 2;
+
+ private static Rect sTmpRect = new Rect();
/**
* The type of insets to provide.
@@ -77,29 +83,25 @@
public Insets insetsSize = null;
/**
- * The provided frame based on the source frame. The result will be used as the insets
- * size to IME window. Only one side should be set.
+ * If null, the size set in insetsSize will be applied to all window types. If it contains
+ * element of some types, the insets reported to the window with that types will be overridden.
*/
- public Insets imeInsetsSize = null;
+ public InsetsSizeOverride[] insetsSizeOverrides = null;
public InsetsFrameProvider(int type) {
this(type, SOURCE_FRAME, null, null);
}
public InsetsFrameProvider(int type, Insets insetsSize) {
- this(type, SOURCE_FRAME, insetsSize, insetsSize);
- }
-
- public InsetsFrameProvider(int type, Insets insetsSize, Insets imeInsetsSize) {
- this(type, SOURCE_FRAME, insetsSize, imeInsetsSize);
+ this(type, SOURCE_FRAME, insetsSize, null);
}
public InsetsFrameProvider(int type, int source, Insets insetsSize,
- Insets imeInsetsSize) {
+ InsetsSizeOverride[] insetsSizeOverride) {
this.type = type;
this.source = source;
this.insetsSize = insetsSize;
- this.imeInsetsSize = imeInsetsSize;
+ this.insetsSizeOverrides = insetsSizeOverride;
}
@Override
@@ -127,8 +129,8 @@
if (insetsSize != null) {
sb.append(", insetsSize=").append(insetsSize);
}
- if (imeInsetsSize != null) {
- sb.append(", imeInsetsSize=").append(imeInsetsSize);
+ if (insetsSizeOverrides != null) {
+ sb.append(", insetsSizeOverrides=").append(Arrays.toString(insetsSizeOverrides));
}
sb.append("}");
return sb.toString();
@@ -141,8 +143,8 @@
if ((insetsSizeModified & HAS_INSETS_SIZE) != 0) {
insetsSize = Insets.CREATOR.createFromParcel(in);
}
- if ((insetsSizeModified & HAS_IME_INSETS_SIZE) != 0) {
- imeInsetsSize = Insets.CREATOR.createFromParcel(in);
+ if ((insetsSizeModified & HAS_INSETS_SIZE_OVERRIDE) != 0) {
+ insetsSizeOverrides = in.createTypedArray(InsetsSizeOverride.CREATOR);
}
}
@@ -152,8 +154,8 @@
if (insetsSize != null) {
insetsSizeModified |= HAS_INSETS_SIZE;
}
- if (imeInsetsSize != null) {
- insetsSizeModified |= HAS_IME_INSETS_SIZE;
+ if (insetsSizeOverrides != null) {
+ insetsSizeModified |= HAS_INSETS_SIZE_OVERRIDE;
}
out.writeInt(insetsSizeModified);
out.writeInt(type);
@@ -161,8 +163,8 @@
if (insetsSize != null) {
insetsSize.writeToParcel(out, flags);
}
- if (imeInsetsSize != null) {
- imeInsetsSize.writeToParcel(out, flags);
+ if (insetsSizeOverrides != null) {
+ out.writeTypedArray(insetsSizeOverrides, flags);
}
}
@@ -177,16 +179,12 @@
InsetsFrameProvider other = (InsetsFrameProvider) o;
return type == other.type && source == other.source
&& Objects.equals(insetsSize, other.insetsSize)
- && Objects.equals(imeInsetsSize, other.imeInsetsSize);
+ && Arrays.equals(insetsSizeOverrides, other.insetsSizeOverrides);
}
@Override
public int hashCode() {
- int result = type;
- result = 31 * result + source;
- result = 31 * result + (insetsSize != null ? insetsSize.hashCode() : 0);
- result = 31 * result + (imeInsetsSize != null ? imeInsetsSize.hashCode() : 0);
- return result;
+ return Objects.hash(type, source, insetsSize, Arrays.hashCode(insetsSizeOverrides));
}
public static final @android.annotation.NonNull Parcelable.Creator<InsetsFrameProvider>
@@ -201,5 +199,96 @@
return new InsetsFrameProvider[size];
}
};
+
+ public static void calculateInsetsFrame(Rect displayFrame, Rect containerBounds,
+ Rect displayCutoutSafe, Rect inOutFrame, int source, Insets insetsSize,
+ @WindowManager.LayoutParams.PrivateFlags int privateFlags) {
+ boolean extendByCutout = false;
+ if (source == InsetsFrameProvider.SOURCE_DISPLAY) {
+ inOutFrame.set(displayFrame);
+ } else if (source == InsetsFrameProvider.SOURCE_CONTAINER_BOUNDS) {
+ inOutFrame.set(containerBounds);
+ } else {
+ extendByCutout = (privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0;
+ }
+ if (insetsSize == null) {
+ return;
+ }
+ // Only one side of the provider shall be applied. Check in the order of left - top -
+ // right - bottom, only the first non-zero value will be applied.
+ if (insetsSize.left != 0) {
+ inOutFrame.right = inOutFrame.left + insetsSize.left;
+ } else if (insetsSize.top != 0) {
+ inOutFrame.bottom = inOutFrame.top + insetsSize.top;
+ } else if (insetsSize.right != 0) {
+ inOutFrame.left = inOutFrame.right - insetsSize.right;
+ } else if (insetsSize.bottom != 0) {
+ inOutFrame.top = inOutFrame.bottom - insetsSize.bottom;
+ } else {
+ inOutFrame.setEmpty();
+ }
+
+ if (extendByCutout) {
+ WindowLayout.extendFrameByCutout(displayCutoutSafe, displayFrame, inOutFrame, sTmpRect);
+ }
+ }
+
+ /**
+ * Class to describe the insets size to be provided to window with specific window type. If not
+ * used, same insets size will be sent as instructed in the insetsSize and source.
+ */
+ public static class InsetsSizeOverride implements Parcelable {
+ public final int windowType;
+ public Insets insetsSize;
+
+ protected InsetsSizeOverride(Parcel in) {
+ windowType = in.readInt();
+ insetsSize = in.readParcelable(null, android.graphics.Insets.class);
+ }
+
+ public InsetsSizeOverride(int type, Insets size) {
+ windowType = type;
+ insetsSize = size;
+ }
+
+ public static final Creator<InsetsSizeOverride> CREATOR =
+ new Creator<InsetsSizeOverride>() {
+ @Override
+ public InsetsSizeOverride createFromParcel(Parcel in) {
+ return new InsetsSizeOverride(in);
+ }
+
+ @Override
+ public InsetsSizeOverride[] newArray(int size) {
+ return new InsetsSizeOverride[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(windowType);
+ out.writeParcelable(insetsSize, flags);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(32);
+ sb.append("TypedInsetsSize: {");
+ sb.append("windowType=").append(windowType);
+ sb.append(", insetsSize=").append(insetsSize);
+ sb.append("}");
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(windowType, insetsSize);
+ }
+ }
}
diff --git a/core/java/android/view/WindowLayout.java b/core/java/android/view/WindowLayout.java
index 0941ee8..57a0330 100644
--- a/core/java/android/view/WindowLayout.java
+++ b/core/java/android/view/WindowLayout.java
@@ -274,7 +274,7 @@
}
if (extendedByCutout) {
- extendFrameByCutout(attrs.gravity, displayCutoutSafe, outDisplayFrame, outFrame,
+ extendFrameByCutout(displayCutoutSafe, outDisplayFrame, outFrame,
mTempRect);
}
@@ -291,7 +291,7 @@
+ " requestedVisibilities=" + requestedVisibilities);
}
- public static void extendFrameByCutout(int gravity, Rect displayCutoutSafe,
+ public static void extendFrameByCutout(Rect displayCutoutSafe,
Rect displayFrame, Rect inOutFrame, Rect tempRect) {
if (displayCutoutSafe.contains(inOutFrame)) {
return;
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 25445ab..ac4c2ea 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -404,9 +404,10 @@
try {
root.setView(view, wparams, panelParentView, userId);
} catch (RuntimeException e) {
+ final int viewIndex = findViewLocked(view, false);
// BadTokenException or InvalidDisplayException, clean up.
- if (index >= 0) {
- removeViewLocked(index, true);
+ if (viewIndex >= 0) {
+ removeViewLocked(viewIndex, true);
}
throw e;
}
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index 4af28ea..1520ea5 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -41,7 +41,12 @@
static JNIEnv* getenv(JavaVM* vm) {
JNIEnv* env;
- if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ auto result = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+ if (result == JNI_EDETACHED) {
+ if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
+ LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
+ }
+ } else if (result != JNI_OK) {
LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
}
return env;
@@ -60,28 +65,22 @@
}
~TransactionHangCallbackWrapper() {
- if (mTransactionHangObject) {
- getenv()->DeleteGlobalRef(mTransactionHangObject);
+ if (mTransactionHangObject != nullptr) {
+ getenv(mVm)->DeleteGlobalRef(mTransactionHangObject);
mTransactionHangObject = nullptr;
}
}
void onTransactionHang(bool isGpuHang) {
if (mTransactionHangObject) {
- getenv()->CallVoidMethod(mTransactionHangObject,
- gTransactionHangCallback.onTransactionHang, isGpuHang);
+ getenv(mVm)->CallVoidMethod(mTransactionHangObject,
+ gTransactionHangCallback.onTransactionHang, isGpuHang);
}
}
private:
JavaVM* mVm;
jobject mTransactionHangObject;
-
- JNIEnv* getenv() {
- JNIEnv* env;
- mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
- return env;
- }
};
static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName,
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 92ac389..505ef30 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -578,7 +578,7 @@
optional WindowStateProto pending_control_target = 6;
optional WindowStateProto fake_control_target = 7;
optional .android.view.SurfaceControlProto captured_leash = 8;
- optional .android.graphics.RectProto ime_overridden_frame = 9;
+ optional .android.graphics.RectProto ime_overridden_frame = 9 [deprecated=true];
optional bool is_leash_ready_for_dispatching = 10;
optional bool client_visible = 11;
optional bool server_visible = 12;
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 6706e4e..f01e2e8 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -577,12 +577,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-1521427940": {
- "message": "commitVisibility: %s: visible=%b mVisibleRequested=%b",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS",
- "at": "com\/android\/server\/wm\/ActivityRecord.java"
- },
"-1517908912": {
"message": "requestScrollCapture: caught exception dispatching to window.token=%s",
"level": "WARN",
@@ -1513,6 +1507,12 @@
"group": "WM_DEBUG_FOCUS_LIGHT",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "-636553602": {
+ "message": "commitVisibility: %s: visible=%b visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_APP_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"-635082269": {
"message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b",
"level": "INFO",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 3f518c7..e0ad9cb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -23,6 +23,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
+import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -541,7 +542,8 @@
// Notify the recent tasks that a task has been removed
mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskRemoved(taskInfo));
- if (appearedInfo.getLeash() != null) {
+ if (!ENABLE_SHELL_TRANSITIONS && (appearedInfo.getLeash() != null)) {
+ // Preemptively clean up the leash only if shell transitions are not enabled
appearedInfo.getLeash().release();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt
index b483fe0..312af4f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/PhysicsAnimator.kt
@@ -829,8 +829,12 @@
/** Cancels all in progress animations on all properties. */
fun cancel() {
- cancelAction(flingAnimations.keys)
- cancelAction(springAnimations.keys)
+ if (flingAnimations.size > 0) {
+ cancelAction(flingAnimations.keys)
+ }
+ if (springAnimations.size > 0) {
+ cancelAction(springAnimations.keys)
+ }
}
/** Cancels in progress animations on the provided properties only. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/README.txt b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/README.txt
deleted file mode 100644
index 1cd69ed..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/README.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-The dagger modules in this directory can be included by the host SysUI using the Shell library for
-explicity injection of Shell components. Apps using this library are not required to use these
-dagger modules for setup, but it is recommended for them to include them as needed.
-
-The modules are currently inherited as such:
-
-+- WMShellBaseModule (common shell features across SysUI)
- |
- +- WMShellModule (handheld)
- |
- +- TvPipModule (tv pip)
- |
- +- TvWMShellModule (tv)
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/README.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/README.md
new file mode 100644
index 0000000..73a7348
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/README.md
@@ -0,0 +1,18 @@
+# Window Manager Shell Readme
+
+The following docs present more detail about the implementation of the WMShell library (in no
+particular order):
+
+1) [What is the Shell](overview.md)
+2) [Integration with SystemUI & Launcher](sysui.md)
+3) [Usage of Dagger](dagger.md)
+4) [Threading model in the Shell](threading.md)
+5) [Making changes in the Shell](changes.md)
+6) [Extending the Shell for Products/OEMs](extending.md)
+7) [Debugging in the Shell](debugging.md)
+8) [Testing in the Shell](testing.md)
+
+Todo
+- Per-feature docs
+- Feature flagging
+- Best practices
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md
new file mode 100644
index 0000000..f4e2f20
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md
@@ -0,0 +1,73 @@
+# Making changes in the Shell
+
+---
+
+## Code reviews
+
+In addition to the individual reviewers who are most familiar with the changes you are making,
+please also add [wm-code-reviewers@google.com](http://g/wm-code-reviewers) to keep other WM folks
+in the loop.
+
+## Adding new code
+
+### Internal Shell utility classes
+If the new component is used only within the WMShell library, then there are no special
+considerations, go ahead and add it (in the `com.android.wm.shell.common` package for example)
+and make sure the appropriate [unit tests](testing.md) are added.
+
+### Internal Shell components
+If the new component is to be used by other components/features within the Shell library, then
+you can create an appropriate package for this component to add your new code. The current
+pattern is to have a single `<Component name>Controller` that handles the initialization of the
+component.
+
+As mentioned in the [Dagger usage](dagger.md) docs, you need to determine whether it should go into:
+- `WMShellBaseModule` for components that other base & product components will depend on
+- or `WMShellModule`, `TvWmShellModule`, etc. for product specific components that no base
+ components depend on
+
+### SysUI accessible components
+In addition to doing the above, you will also need to provide an interface for calling to SysUI
+from the Shell and vice versa. The current pattern is to have a parallel `Optional<Component name>`
+interface that the `<Component name>Controller` implements and handles on the main Shell thread.
+
+In addition, because components accessible to SysUI injection are explicitly listed, you'll have to
+add an appropriate method in `WMComponent` to get the interface and update the `Builder` in
+`SysUIComponent` to take the interface so it can be injected in SysUI code. The binding between
+the two is done in `SystemUIFactory#init()` which will need to be updated as well.
+
+### Launcher accessible components
+Because Launcher is not a part of SystemUI and is a separate process, exposing controllers to
+Launcher requires a new AIDL interface to be created and implemented by the controller. The
+implementation of the stub interface in the controller otherwise behaves similar to the interface
+to SysUI where it posts the work to the main Shell thread.
+
+### Component initialization
+To initialize the component:
+- On the Shell side, update `ShellInitImpl` to get a signal to initialize when the SysUI is started
+- On the SysUI side, update `WMShell` to setup any bindings for the component that depend on
+ SysUI code
+
+### General Do's & Dont's
+Do:
+- Do add unit tests for all new components
+- Do keep controllers simple and break them down as needed
+
+Don't:
+- **Don't** do initialization in the constructor, only do initialization in the init callbacks.
+ Otherwise it complicates the building of the dependency graph.
+- **Don't** create dependencies from base-module components on specific features (the base module
+ is intended for use with all products)
+ - Try adding a mechanism to register and listen for changes from the base module component instead
+- **Don't** add blocking synchronous calls in the SysUI interface between Shell & SysUI
+ - Try adding a push-mechanism to share data, or an async callback to request data
+
+### Exposing shared code for use in Launcher
+Launcher doesn't currently build against the Shell library, but needs to have access to some shared
+AIDL interfaces and constants. Currently, all AIDL files, and classes under the
+`com.android.wm.shell.util` package are automatically built into the `SystemUISharedLib` that
+Launcher uses.
+
+If the new code doesn't fall into those categories, they can be added explicitly in the Shell's
+[Android.bp](frameworks/base/libs/WindowManager/Shell/Android.bp) file under the
+`wm_shell_util-sources` filegroup.
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/dagger.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/dagger.md
new file mode 100644
index 0000000..6c01d96
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/dagger.md
@@ -0,0 +1,50 @@
+# Usage of Dagger in the Shell library
+
+---
+
+## Dependencies
+
+Dagger is not required to use the Shell library, but it has a lot of obvious benefits:
+
+- Not having to worry about how to instantiate all the dependencies of a class, especially as
+ dependencies evolve (ie. product controller depends on base controller)
+- Can create boundaries within the same app to encourage better code modularity
+
+As such, the Shell also tries to provide some reasonable out-of-the-box modules for use with Dagger.
+
+## Modules
+
+All the Dagger related code in the Shell can be found in the `com.android.wm.shell.dagger` package,
+this is intentional as it keeps the "magic" in a single location. The explicit nature of how
+components in the shell are provided is as a result a bit more verbose, but it makes it easy for
+developers to jump into a few select files and understand how different components are provided
+(especially as products override components).
+
+The module dependency tree looks a bit like:
+- [WMShellConcurrencyModule](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java)
+ (provides threading-related components)
+ - [WMShellBaseModule](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java)
+ (provides components that are likely common to all products, ie. DisplayController,
+ Transactions, etc.)
+ - [WMShellModule](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java)
+ (phone/tablet specific components only)
+ - [TvPipModule](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java)
+ (PIP specific components for TV)
+ - [TvWMShellModule](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java)
+ (TV specific components only)
+ - etc.
+
+Ideally features could be abstracted out into their own modules and included as needed by each
+product.
+
+## Overriding base components
+
+In some rare cases, there are base components that can change behavior depending on which
+product it runs on. If there are hooks that can be added to the component, that is the
+preferable approach.
+
+The alternative is to use the [@DynamicOverride](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/DynamicOverride.java)
+annotation to allow the product module to provide an implementation that the base module can
+reference. This is most useful if the existence of the entire component is controlled by the
+product and the override implementation is optional (there is a default implementation). More
+details can be found in the class's javadoc.
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
new file mode 100644
index 0000000..52f0c42
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/debugging.md
@@ -0,0 +1,69 @@
+# Debugging in the Shell
+
+---
+
+## Logging & ProtoLogs
+
+The interactions in the Shell can be pretty complicated, so having good logging is crucial to
+debugging problems that arise (especially in dogfood). The Shell uses the same efficient Protolog
+mechanism as WM Core, which can be enabled at runtime on debug devices.
+
+**TLDR** Don’t use Logs or Slogs except for error cases, Protologs are much more flexible,
+easy to add and easy to use
+
+### Adding a new ProtoLog
+Update `ShellProtoLogGroup` to include a new log group (ie. NEW_FEATURE) for the content you want to
+log. ProtoLog log calls mirror Log.v/d/e(), and take a format message and arguments:
+```java
+ProtoLog.v(NEW_FEATURE, "Test log w/ params: %d %s", 1, “a”)
+```
+This code itself will not compile by itself, but the `protologtool` will preprocess the file when
+building to check the log state (is enabled) before printing the print format style log.
+
+**Notes**
+- ProtoLogs currently only work from soong builds (ie. via make/mp). We need to reimplement the
+ tool for use with SysUI-studio
+- Non-text ProtoLogs are not currently supported with the Shell library (you can't view them with
+ traces in Winscope)
+
+### Enabling ProtoLog command line logging
+Run these commands to enable protologs for both WM Core and WM Shell to print to logcat.
+```shell
+adb shell wm logging enable-text NEW_FEATURE
+adb shell wm logging disable-text NEW_FEATURE
+```
+
+## Winscope Tracing
+
+The Winscope tool is extremely useful in determining what is happening on-screen in both
+WindowManager and SurfaceFlinger. Follow [go/winscope](http://go/winscope-help) to learn how to
+use the tool.
+
+In addition, there is limited preliminary support for Winscope tracing componetns in the Shell,
+which involves adding trace fields to [wm_shell_trace.proto](frameworks/base/libs/WindowManager/Shell/proto/wm_shell_trace.proto)
+file and ensure it is updated as a part of `WMShell#writeToProto`.
+
+Tracing can be started via the shell command (to be added to the Winscope tool as needed):
+```shell
+adb shell cmd statusbar tracing start
+adb shell cmd statusbar tracing stop
+```
+
+## Dumps
+
+Because the Shell library is built as a part of SystemUI, dumping the state is currently done as a
+part of dumping the SystemUI service. Dumping the Shell specific data can be done by specifying the
+WMShell SysUI service:
+
+```shell
+adb shell dumpsys activity service SystemUIService WMShell
+```
+
+If information should be added to the dump, make updates to:
+- `WMShell` if you are dumping SysUI state
+- `ShellCommandHandler` if you are dumping Shell state
+
+## Debugging in Android Studio
+
+If you are using the [go/sysui-studio](http://go/sysui-studio) project, then you can debug Shell
+code directly from Android Studio like any other app.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/extending.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/extending.md
new file mode 100644
index 0000000..061ae00e
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/extending.md
@@ -0,0 +1,13 @@
+# Extending the Shell for Products/OEMs
+
+---
+
+## General Do's & Dont's
+
+Do:
+-
+
+Don't
+- **Don't** override classes provided by WMShellBaseModule, it makes it difficult to make
+ simple changes to the Shell library base modules which are shared by all products
+ - If possible add mechanisms to modify the base class behavior
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/overview.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/overview.md
new file mode 100644
index 0000000..a88ef6a
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/overview.md
@@ -0,0 +1,58 @@
+# What is the WindowManager Shell
+
+---
+
+## Motivation
+
+The primary motivation for the WindowManager Shell (WMShell) library is to effectively scale
+WindowManager by making it easy™ and safe to create windowing features to fit the needs of
+various Android products and form factors.
+
+To achieve this, WindowManager separates the policy of managing windows (WMCore) from the
+presentation of surfaces (WMShell) and provides a minimal interface boundary for the two to
+communicate.
+
+## Who is using the library?
+
+Currently, the WMShell library is used to drive the windowing experience on handheld
+(phones & tablets), TV, Auto, Arc++, and Wear to varying degrees.
+
+## Where does the code live
+
+The core WMShell library code is currently located in the [frameworks/base/libs/WindowManager/Shell](frameworks/base/libs/WindowManager/Shell)
+directory and is included as a part dependency of the host SystemUI apk.
+
+## How do I build the Shell library
+
+The library can be built directly by running (using [go/makepush](http://go/makepush)):
+```shell
+mp :WindowManager-Shell
+```
+But this is mainly useful for inspecting the contents of the library or verifying it builds. The
+various targets can be found in the Shell library's [Android.bp](frameworks/base/libs/WindowManager/Shell/Android.bp)
+file.
+
+Normally, you would build it as a part of the host SystemUI, for example via commandline:
+```shell
+# Phone SystemUI variant
+mp sysuig
+# Building Shell & SysUI changes along w/ framework changes
+mp core services sysuig
+```
+
+Or preferably, if you are making WMShell/SysUI only changes (no other framework changes), then
+building via [go/sysui-studio](http://go/sysui-studio) allows for very quick iteration (one click
+build and push of SysUI in < 30s).
+
+If you are making framework changes and are using `aidegen` to set up your platform IDE, make sure
+to include the appropriate directories to build, for example:
+```shell
+# frameworks/base will include base/libs/WindowManager/Shell and base/packages/SystemUI
+aidegen frameworks/base \
+ vendor/<oem>/packages/SystemUI \
+ ...
+```
+
+## Other useful links
+- [go/o-o-summit-20](go/o-o-summit-20) (Video presentations from the WM team)
+- [go/o-o-summit-21](go/o-o-summit-21)
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md
new file mode 100644
index 0000000..68f970f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md
@@ -0,0 +1,55 @@
+# Shell & SystemUI
+
+---
+
+## Setup
+
+The SystemUI of various products depend on and build against the WM Shell library. To ensure
+that we don't inadvertently build dependencies between the Shell library and one particular
+product (ie. handheld SysUI), we deliberately separate the initialization of the WM Shell
+component from the SysUI component when set up through Dagger.
+
+**TLDR** Initialize everything as needed in the WM component scope and export only well
+defined interfaces to SysUI.
+
+## Initialization
+
+There are more details in the Dagger docs, but the general overview of the SysUI/Shell
+initialization flow is such:
+
+1) SysUI Global scope is initialize (see `GlobalModule` and its included modules)
+2) WM Shell scope is initialized, for example
+ 1) On phones: `WMComponent` includes `WMShellModule` which includes `WMShellBaseModule`
+ (common to all SysUI)
+ 2) On TVs: `TvWMComponent` includes `TvWMShellModule` which includes `WMShellBaseModule`
+ 3) etc.
+3) SysUI explicitly passes interfaces provided from the `WMComponent` to `SysUIComponent` via
+ the `SysUIComponent#Builder`, then builds the SysUI scoped components
+4) `WMShell` is the SystemUI “service” (in the SysUI scope) that initializes with the app after the
+SystemUI part of the dependency graph has been created. It contains the binding code between the
+interfaces provided by the Shell and the rest of SystemUI.
+5) SysUI can inject the interfaces into its own components
+
+More detail can be found in [go/wm-sysui-dagger](http://go/wm-sysui-dagger).
+
+## Interfaces to Shell components
+
+Within the same process, the WM Shell components can be running on a different thread than the main
+SysUI thread (disabled on certain products). This introduces challenges where we have to be
+careful about how SysUI calls into the Shell and vice versa.
+
+As a result, we enforce explicit interfaces between SysUI and Shell components, and the
+implementations of the interfaces on each side need to post to the right thread before it calls
+into other code.
+
+For example, you might have:
+1) (Shell) ShellFeature interface to be used from SysUI
+2) (Shell) ShellFeatureController handles logic, implements ShellFeature interface and posts to
+ main Shell thread
+3) SysUI application init injects Optional<ShellFeature> as an interface to SysUI to call
+4) (SysUI) SysUIFeature depends on ShellFeature interface
+5) (SysUI) SysUIFeature injects Optional<ShellFeature>, and sets up a callback for the Shell to
+ call, and the callback posts to the main SysUI thread
+
+Adding an interface to a Shell component may seem like a lot of boiler plate, but is currently
+necessary to maintain proper threading and logic isolation.
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/testing.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/testing.md
new file mode 100644
index 0000000..8a80333
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/testing.md
@@ -0,0 +1,49 @@
+# Testing
+
+---
+
+## Unit tests
+
+New WM Shell unit tests can be added to the
+[Shell/tests/unittest](frameworks/base/libs/WindowManager/Shell/tests/unittest) directory, and can
+be run via command line using `atest`:
+```shell
+atest WMShellUnitTests
+```
+
+If you use the SysUI Studio project, you can run and debug tests directly in the source files
+(click on the little arrows next to the test class or test method).
+
+These unit tests are run as a part of WindowManager presubmit, and the dashboards for these unit
+tests tests can be found at [go/wm-tests](http://go/wm-tests).
+
+This [GCL file](http://go/wm-unit-tests-gcl) configures the tests being run on the server.
+
+## Flicker tests
+
+Flicker tests are tests that perform actions and make assertions on the state in Window Manager
+and SurfaceFlinger traces captured during the run.
+
+New WM Shell Flicker tests can be added to the
+[Shell/tests/flicker](frameworks/base/libs/WindowManager/Shell/tests/flicker) directory, and can
+be run via command line using `atest`:
+```shell
+atest WMShellFlickerTests
+```
+
+**Note**: Currently Flicker tests can only be run from the commandline and not via SysUI Studio
+
+A subset of the flicker tests tests are run as a part of WindowManager presubmit, and the
+dashboards for these tests tests can be found at [go/wm-tests-flicker](http://go/wm-tests-flicker).
+
+## CTS tests
+
+Some windowing features also have CTS tests to ensure consistent behavior across OEMs. For example:
+- Picture-in-Picture:
+ [PinnedStackTests](cts/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java)
+- etc.
+
+These can also be run via commandline only using `atest`, for example:
+```shell
+atest PinnedStackTests
+```
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/threading.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/threading.md
new file mode 100644
index 0000000..eac74889
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/threading.md
@@ -0,0 +1,83 @@
+# Threading
+
+---
+
+## Boundaries
+
+```text
+ Thread boundary
+ |
+ WM Shell | SystemUI
+ |
+ |
+FeatureController <-> FeatureInterface <--|--> WMShell <-> SysUI
+ | (^post to shell thread) | (^post to main thread)
+ ... |
+ | |
+ OtherControllers |
+```
+
+## Threads
+
+We currently have multiple threads in use in the Shell library depending on the configuration by
+the product.
+- SysUI main thread (standard main thread)
+- `ShellMainThread` (only used if the resource `config_enableShellMainThread` is set true
+ (ie. phones))
+ - This falls back to the SysUI main thread otherwise
+ - **Note**:
+ - This thread runs with `THREAD_PRIORITY_DISPLAY` priority since so many windowing-critical
+ components depend on it
+ - This is also the UI thread for almost all UI created by the Shell
+ - The Shell main thread Handler (and the Executor that wraps it) is async, so
+ messages/runnables used via this Handler are handled immediately if there is no sync
+ messages prior to it in the queue.
+- `ShellBackgroundThread` (for longer running tasks where we don't want to block the shell main
+ thread)
+ - This is always another thread even if config_enableShellMainThread is not set true
+ - **Note**:
+ - This thread runs with `THREAD_PRIORITY_BACKGROUND` priority
+- `ShellAnimationThread` (currently only used for Transitions and Splitscreen, but potentially all
+ animations could be offloaded here)
+- `ShellSplashScreenThread` (only for use with splashscreens)
+
+## Dagger setup
+
+The threading-related components are provided by the [WMShellConcurrencyModule](frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java),
+for example, the Executors and Handlers for the various threads that are used. You can request
+an executor of the necessary type by using the appropriate annotation for each of the threads (ie.
+`@ShellMainThread Executor`) when injecting into your Shell component.
+
+To get the SysUI main thread, you can use the `@Main` annotation.
+
+## Best practices
+
+### Components
+- Don't do initialization in the Shell component constructors
+ - If the host SysUI is not careful, it may construct the WMComponent dependencies on the main
+ thread, and this reduces the likelihood that components will intiailize on the wrong thread
+ in such cases
+- Be careful of using CountDownLatch and other blocking synchronization mechanisms in Shell code
+ - If the Shell main thread is not a separate thread, this will cause a deadlock
+- Callbacks, Observers, Listeners to any non-shell component should post onto main Shell thread
+ - This includes Binder calls, SysUI calls, BroadcastReceivers, etc. Basically any API that
+ takes a runnable should either be registered with the right Executor/Handler or posted to
+ the main Shell thread manually
+- Since everything in the Shell runs on the main Shell thread, you do **not** need to explicitly
+ `synchronize` your code (unless you are trying to prevent reentrantcy, but that can also be
+ done in other ways)
+
+### Handlers/Executors
+- You generally **never** need to create Handlers explicitly, instead inject `@ShellMainThread
+ ShellExecutor` instead
+ - This is a common pattern to defer logic in UI code, but the Handler created wraps the Looper
+ that is currently running, which can be wrong (see above for initialization vs construction)
+- That said, sometimes Handlers are necessary because Framework API only takes Handlers or you
+ want to dedupe multiple messages
+ - In such cases inject `@ShellMainThread Handler` or use view.getHandler() which should be OK
+ assuming that the view root was initialized on the main Shell thread
+- **Never use Looper.getMainLooper()**
+ - It's likely going to be wrong, you can inject `@Main ShellExecutor` to get the SysUI main thread
+
+### Testing
+- You can use a `TestShellExecutor` to control the processing of messages
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index f1e2323..3dd0032 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -26,11 +26,13 @@
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_MULTI_WINDOW;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP;
+import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
@@ -146,6 +148,7 @@
@Test
public void testTaskLeashReleasedAfterVanished() throws RemoteException {
+ assumeFalse(ENABLE_SHELL_TRANSITIONS);
RunningTaskInfo taskInfo = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
SurfaceControl taskLeash = new SurfaceControl.Builder(new SurfaceSession())
.setName("task").build();
diff --git a/packages/SystemUI/res/drawable/qs_battery_saver_icon_off.xml b/packages/SystemUI/res/drawable/qs_battery_saver_icon_off.xml
new file mode 100644
index 0000000..7b9f23d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_battery_saver_icon_off.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="183"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="12"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:pathData=" M3.67 -8 C3.67,-8 2,-8 2,-8 C2,-8 2,-10 2,-10 C2,-10 -2,-10 -2,-10 C-2,-10 -2,-8 -2,-8 C-2,-8 -3.67,-8 -3.67,-8 C-4.4,-8 -5,-7.4 -5,-6.67 C-5,-6.67 -5,8.66 -5,8.66 C-5,9.4 -4.4,10 -3.67,10 C-3.67,10 3.66,10 3.66,10 C4.4,10 5,9.4 5,8.67 C5,8.67 5,-6.67 5,-6.67 C5,-7.4 4.4,-8 3.67,-8c "
+ android:strokeAlpha="1"
+ android:strokeColor="#ffffff"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2" />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M2 -10 C2,-10 2,-7 2,-7 C2,-7 -2,-7 -2,-7 C-2,-7 -2,-10 -2,-10 C-2,-10 2,-10 2,-10c " />
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M3 2 C3,2 1,2 1,2 C1,2 1,4 1,4 C1,4 -1,4 -1,4 C-1,4 -1,2 -1,2 C-1,2 -3,2 -3,2 C-3,2 -3,0 -3,0 C-3,0 -1,0 -1,0 C-1,0 -1,-2 -1,-2 C-1,-2 1,-2 1,-2 C1,-2 1,0 1,0 C1,0 3,0 3,0 C3,0 3,2 3,2c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/qs_battery_saver_icon_on.xml b/packages/SystemUI/res/drawable/qs_battery_saver_icon_on.xml
new file mode 100644
index 0000000..5e4af39
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_battery_saver_icon_on.xml
@@ -0,0 +1,636 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_4_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillAlpha"
+ android:startOffset="317"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_4_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:pathData="M 0,0.875C 0,-0.9690000000000001 0,-8.344000000000001 0,-10.188"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_4_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="112"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillAlpha"
+ android:startOffset="250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillAlpha"
+ android:startOffset="550"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:pathData="M -0.875,9C -0.854,6.156000000000001 -0.896,11.844 -0.875,9"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="550"
+ android:pathData="M -0.875,9C -0.854,6.156000000000001 -0.771,-5.218 -0.75,-8.062"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="83">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="67"
+ android:valueTo="67"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="550"
+ android:propertyName="rotation"
+ android:startOffset="83"
+ android:valueFrom="67"
+ android:valueTo="192"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillAlpha"
+ android:startOffset="417"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="267"
+ android:propertyName="fillAlpha"
+ android:startOffset="500"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillAlpha"
+ android:startOffset="767"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:pathData="M 2.125,9.375C 2.146,6.468999999999999 2.104,12.281 2.125,9.375"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:pathData="M 2.125,9.375C 2.146,6.468999999999999 2.229,-5.155999999999999 2.25,-8.062"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="250">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="28"
+ android:valueTo="28"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="rotation"
+ android:startOffset="250"
+ android:valueFrom="28"
+ android:valueTo="153"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="533"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillAlpha"
+ android:startOffset="533"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="fillAlpha"
+ android:startOffset="617"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillAlpha"
+ android:startOffset="867"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="350"
+ android:pathData="M -2,10C -2,6.99 -2,13.01 -2,10"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:pathData="M -2,10C -2,6.99 -2,-5.052 -2,-8.062"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="350">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="350"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="28"
+ android:valueTo="28"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="rotation"
+ android:startOffset="350"
+ android:valueFrom="28"
+ android:valueTo="153"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="883"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillAlpha"
+ android:startOffset="883"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="667"
+ android:pathData="M 0,11.5C 0,9.729 0,13.271 0,11.5"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="667"
+ android:pathData="M 0,11.5C 0,9.729 0,2.646 0,0.875"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="667">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="667"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-48"
+ android:valueTo="-48"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="667"
+ android:propertyName="rotation"
+ android:startOffset="667"
+ android:valueFrom="-48"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1350"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_5_G"
+ android:translateX="12"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_5_G_D_0_P_0"
+ android:pathData=" M3.67 -8 C3.67,-8 2,-8 2,-8 C2,-8 2,-10 2,-10 C2,-10 -2,-10 -2,-10 C-2,-10 -2,-8 -2,-8 C-2,-8 -3.67,-8 -3.67,-8 C-4.4,-8 -5,-7.4 -5,-6.67 C-5,-6.67 -5,8.66 -5,8.66 C-5,9.4 -4.4,10 -3.67,10 C-3.67,10 3.66,10 3.66,10 C4.4,10 5,9.4 5,8.67 C5,8.67 5,-6.67 5,-6.67 C5,-7.4 4.4,-8 3.67,-8c "
+ android:strokeAlpha="1"
+ android:strokeColor="#ffffff"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2" />
+ <path
+ android:name="_R_G_L_5_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M2 -10 C2,-10 2,-7 2,-7 C2,-7 -2,-7 -2,-7 C-2,-7 -2,-10 -2,-10 C-2,-10 2,-10 2,-10c " />
+ </group>
+ <group
+ android:name="_R_G_L_4_G_N_6_T_0"
+ android:translateX="12"
+ android:translateY="12">
+ <group
+ android:name="_R_G_L_4_G_T_1"
+ android:rotation="0"
+ android:translateX="0"
+ android:translateY="0.875">
+ <group
+ android:name="_R_G_L_4_G"
+ android:translateY="-0.875">
+ <path
+ android:name="_R_G_L_4_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M3 2 C3,2 1,2 1,2 C1,2 1,4 1,4 C1,4 -1,4 -1,4 C-1,4 -1,2 -1,2 C-1,2 -3,2 -3,2 C-3,2 -3,0 -3,0 C-3,0 -1,0 -1,0 C-1,0 -1,-2 -1,-2 C-1,-2 1,-2 1,-2 C1,-2 1,0 1,0 C1,0 3,0 3,0 C3,0 3,2 3,2c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_3_G_N_6_T_0"
+ android:translateX="12"
+ android:translateY="12">
+ <group
+ android:name="_R_G_L_3_G_T_1"
+ android:rotation="67"
+ android:scaleX="0.7"
+ android:scaleY="0.7"
+ android:translateX="-0.875"
+ android:translateY="9">
+ <group
+ android:name="_R_G_L_3_G"
+ android:translateY="-0.875">
+ <path
+ android:name="_R_G_L_3_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M3 2 C3,2 1,2 1,2 C1,2 1,4 1,4 C1,4 -1,4 -1,4 C-1,4 -1,2 -1,2 C-1,2 -3,2 -3,2 C-3,2 -3,0 -3,0 C-3,0 -1,0 -1,0 C-1,0 -1,-2 -1,-2 C-1,-2 1,-2 1,-2 C1,-2 1,0 1,0 C1,0 3,0 3,0 C3,0 3,2 3,2c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_2_G_N_6_T_0"
+ android:translateX="12"
+ android:translateY="12">
+ <group
+ android:name="_R_G_L_2_G_T_1"
+ android:rotation="28"
+ android:scaleX="0.85"
+ android:scaleY="0.85"
+ android:translateX="2.125"
+ android:translateY="9.375">
+ <group
+ android:name="_R_G_L_2_G"
+ android:translateY="-0.875">
+ <path
+ android:name="_R_G_L_2_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M3 2 C3,2 1,2 1,2 C1,2 1,4 1,4 C1,4 -1,4 -1,4 C-1,4 -1,2 -1,2 C-1,2 -3,2 -3,2 C-3,2 -3,0 -3,0 C-3,0 -1,0 -1,0 C-1,0 -1,-2 -1,-2 C-1,-2 1,-2 1,-2 C1,-2 1,0 1,0 C1,0 3,0 3,0 C3,0 3,2 3,2c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_1_G_N_6_T_0"
+ android:translateX="12"
+ android:translateY="12">
+ <group
+ android:name="_R_G_L_1_G_T_1"
+ android:rotation="28"
+ android:scaleX="0.55"
+ android:scaleY="0.55"
+ android:translateX="-2"
+ android:translateY="10">
+ <group
+ android:name="_R_G_L_1_G"
+ android:translateY="-0.875">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M3 2 C3,2 1,2 1,2 C1,2 1,4 1,4 C1,4 -1,4 -1,4 C-1,4 -1,2 -1,2 C-1,2 -3,2 -3,2 C-3,2 -3,0 -3,0 C-3,0 -1,0 -1,0 C-1,0 -1,-2 -1,-2 C-1,-2 1,-2 1,-2 C1,-2 1,0 1,0 C1,0 3,0 3,0 C3,0 3,2 3,2c " />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_6_T_0"
+ android:translateX="12"
+ android:translateY="12">
+ <group
+ android:name="_R_G_L_0_G_T_1"
+ android:rotation="-48"
+ android:translateX="0"
+ android:translateY="11.5">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateY="-0.875">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M3 2 C3,2 1,2 1,2 C1,2 1,4 1,4 C1,4 -1,4 -1,4 C-1,4 -1,2 -1,2 C-1,2 -3,2 -3,2 C-3,2 -3,0 -3,0 C-3,0 -1,0 -1,0 C-1,0 -1,-2 -1,-2 C-1,-2 1,-2 1,-2 C1,-2 1,0 1,0 C1,0 3,0 3,0 C3,0 3,2 3,2c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/qs_mic_access_off.xml b/packages/SystemUI/res/drawable/qs_mic_access_off.xml
new file mode 100644
index 0000000..63a9444
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_mic_access_off.xml
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M5.05 4.43 C3.98,5.25 3.08,5.53 2.53,5.73 C2.26,5.81 1.98,5.87 1.7,5.9 C1.7,5.9 1.7,9 1.7,9 C1.7,9 -0.3,9 -0.3,9 C-0.3,9 -0.3,5.9 -0.3,5.9 C-2.02,5.65 -3.44,4.88 -4.59,3.59 C-5.73,2.3 -6.3,0.77 -6.3,-1 C-6.3,-1 -4.3,-1 -4.3,-1 C-4.3,0.38 -3.81,1.56 -2.84,2.54 C-1.86,3.51 -0.68,4 0.7,4 C0.88,4 1.06,3.99 1.23,3.96 C1.39,3.94 2.58,3.77 3.61,2.99 C3.61,2.99 5.05,4.43 5.05,4.43c "
+ android:valueTo="M5.02 4.5 C3.59,5.47 2.79,5.64 2.53,5.73 C2.26,5.81 1.98,5.87 1.7,5.9 C1.7,5.9 1.7,9 1.7,9 C1.7,9 -0.3,9 -0.3,9 C-0.3,9 -0.3,5.9 -0.3,5.9 C-2.02,5.65 -3.44,4.88 -4.59,3.59 C-5.73,2.3 -6.3,0.77 -6.3,-1 C-6.3,-1 -4.3,-1 -4.3,-1 C-4.3,0.38 -3.81,1.56 -2.84,2.54 C-1.86,3.51 -0.68,4 0.7,4 C0.88,4 1.06,3.99 1.23,3.96 C1.39,3.94 2.53,3.83 3.58,3.07 C3.58,3.07 5.02,4.5 5.02,4.5c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="44"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M2.31 1.86 C2.31,1.86 1.01,0.55 0.75,0.31 C1.7,0.27 1.7,-0.7 1.7,-0.7 C1.7,-0.7 1.7,-7 1.7,-7 C1.7,-7.28 1.61,-7.52 1.41,-7.71 C1.22,-7.9 0.98,-8 0.7,-8 C0.42,-8 0.18,-7.9 -0.01,-7.71 C-0.2,-7.52 -0.3,-7.28 -0.3,-7 C-0.3,-7 -0.29,-0.66 -0.29,-0.66 C-0.29,-0.66 -2.31,-2.67 -2.31,-2.67 C-2.31,-2.67 -2.3,-7 -2.3,-7 C-2.3,-7.83 -2.01,-8.54 -1.42,-9.12 C-0.84,-9.71 -0.13,-10 0.7,-10 C1.53,-10 2.24,-9.71 2.83,-9.12 C3.41,-8.54 3.7,-7.83 3.7,-7 C3.7,-7 3.7,-1 3.7,-1 C3.7,-0.82 3.7,-0.33 3.64,-0.03 C3.51,0.52 3.23,1.19 2.31,1.86c "
+ android:valueTo="M2.86 1.48 C2.86,1.48 1.58,0.21 1.39,0.03 C1.77,-0.26 1.7,-1.03 1.7,-1.03 C1.7,-1.03 1.7,-7 1.7,-7 C1.7,-7.28 1.61,-7.52 1.41,-7.71 C1.22,-7.9 0.98,-8 0.7,-8 C0.42,-8 0.18,-7.9 -0.01,-7.71 C-0.2,-7.52 -0.3,-7.28 -0.3,-7 C-0.3,-7 -0.29,-1.51 -0.29,-1.51 C-0.29,-1.51 -2.31,-3.5 -2.31,-3.5 C-2.31,-3.5 -2.3,-7 -2.3,-7 C-2.3,-7.83 -2.01,-8.54 -1.42,-9.12 C-0.84,-9.71 -0.13,-10 0.7,-10 C1.53,-10 2.24,-9.71 2.83,-9.12 C3.41,-8.54 3.7,-7.83 3.7,-7 C3.7,-7 3.7,-1 3.7,-1 C3.7,-0.82 3.68,-0.44 3.65,-0.17 C3.61,0.19 3.36,1.05 2.86,1.48c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="39"
+ android:propertyName="pathData"
+ android:startOffset="44"
+ android:valueFrom="M2.86 1.48 C2.86,1.48 1.58,0.21 1.39,0.03 C1.77,-0.26 1.7,-1.03 1.7,-1.03 C1.7,-1.03 1.7,-7 1.7,-7 C1.7,-7.28 1.61,-7.52 1.41,-7.71 C1.22,-7.9 0.98,-8 0.7,-8 C0.42,-8 0.18,-7.9 -0.01,-7.71 C-0.2,-7.52 -0.3,-7.28 -0.3,-7 C-0.3,-7 -0.29,-1.51 -0.29,-1.51 C-0.29,-1.51 -2.31,-3.5 -2.31,-3.5 C-2.31,-3.5 -2.3,-7 -2.3,-7 C-2.3,-7.83 -2.01,-8.54 -1.42,-9.12 C-0.84,-9.71 -0.13,-10 0.7,-10 C1.53,-10 2.24,-9.71 2.83,-9.12 C3.41,-8.54 3.7,-7.83 3.7,-7 C3.7,-7 3.7,-1 3.7,-1 C3.7,-0.82 3.68,-0.44 3.65,-0.17 C3.61,0.19 3.36,1.05 2.86,1.48c "
+ android:valueTo="M3.12 0.99 C3.12,0.99 1.83,-0.26 1.71,-0.38 C1.72,-0.81 1.7,-1.31 1.7,-1.31 C1.7,-1.31 1.7,-7 1.7,-7 C1.7,-7.28 1.61,-7.52 1.41,-7.71 C1.22,-7.9 0.98,-8 0.7,-8 C0.42,-8 0.18,-7.9 -0.01,-7.71 C-0.2,-7.52 -0.3,-7.28 -0.3,-7 C-0.3,-7 -0.29,-2.26 -0.29,-2.26 C-0.29,-2.26 -2.31,-4.23 -2.31,-4.23 C-2.31,-4.23 -2.3,-7 -2.3,-7 C-2.3,-7.83 -2.01,-8.54 -1.42,-9.12 C-0.84,-9.71 -0.13,-10 0.7,-10 C1.53,-10 2.24,-9.71 2.83,-9.12 C3.41,-8.54 3.7,-7.83 3.7,-7 C3.7,-7 3.7,-1 3.7,-1 C3.7,-0.82 3.67,-0.54 3.66,-0.3 C3.63,0.12 3.38,0.7 3.12,0.99c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="pathData"
+ android:startOffset="83"
+ android:valueFrom="M3.12 0.99 C3.12,0.99 1.83,-0.26 1.71,-0.38 C1.72,-0.81 1.7,-1.31 1.7,-1.31 C1.7,-1.31 1.7,-7 1.7,-7 C1.7,-7.28 1.61,-7.52 1.41,-7.71 C1.22,-7.9 0.98,-8 0.7,-8 C0.42,-8 0.18,-7.9 -0.01,-7.71 C-0.2,-7.52 -0.3,-7.28 -0.3,-7 C-0.3,-7 -0.29,-2.26 -0.29,-2.26 C-0.29,-2.26 -2.31,-4.23 -2.31,-4.23 C-2.31,-4.23 -2.3,-7 -2.3,-7 C-2.3,-7.83 -2.01,-8.54 -1.42,-9.12 C-0.84,-9.71 -0.13,-10 0.7,-10 C1.53,-10 2.24,-9.71 2.83,-9.12 C3.41,-8.54 3.7,-7.83 3.7,-7 C3.7,-7 3.7,-1 3.7,-1 C3.7,-0.82 3.67,-0.54 3.66,-0.3 C3.63,0.12 3.38,0.7 3.12,0.99c "
+ android:valueTo="M3.5 -0.05 C3.5,-0.05 1.7,-1.85 1.7,-1.85 C1.7,-1.85 1.7,-1.92 1.7,-1.92 C1.7,-1.92 1.7,-7 1.7,-7 C1.7,-7.28 1.61,-7.52 1.41,-7.71 C1.22,-7.9 0.98,-8 0.7,-8 C0.42,-8 0.18,-7.9 -0.01,-7.71 C-0.2,-7.52 -0.3,-7.28 -0.3,-7 C-0.3,-7 -0.3,-3.85 -0.3,-3.85 C-0.3,-3.85 -2.3,-5.85 -2.3,-5.85 C-2.3,-5.85 -2.3,-7 -2.3,-7 C-2.3,-7.83 -2.01,-8.54 -1.42,-9.12 C-0.84,-9.71 -0.13,-10 0.7,-10 C1.53,-10 2.24,-9.71 2.83,-9.12 C3.41,-8.54 3.7,-7.83 3.7,-7 C3.7,-7 3.7,-1 3.7,-1 C3.7,-0.82 3.68,-0.65 3.64,-0.5 C3.6,-0.35 3.55,-0.2 3.5,-0.05c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M5.04 4.45 C5.04,4.45 3.59,3.02 3.59,3.02 C4.82,1.94 5.31,0.96 5.53,0.3 C5.64,-0.12 5.7,-0.55 5.7,-1 C5.7,-1 7.7,-1 7.7,-1 C7.7,-0.27 7.59,0.43 7.38,1.09 C7.16,1.75 6.51,3.17 5.04,4.45c "
+ android:valueTo="M6.45 2.95 C6.45,2.95 5,1.5 5,1.5 C5.23,1.12 5.41,0.72 5.53,0.3 C5.64,-0.12 5.7,-0.55 5.7,-1 C5.7,-1 7.7,-1 7.7,-1 C7.7,-0.27 7.59,0.43 7.38,1.09 C7.16,1.75 6.85,2.37 6.45,2.95c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M-0.29 -0.71 C-0.29,-0.42 -0.19,-0.19 0,0.01 C0.19,0.2 0.43,0.29 0.71,0.29 C0.76,0.31 0.75,0.31 0.78,0.3 C1.14,0.67 1.92,1.43 2.34,1.85 C2.03,2.04 1.55,2.29 0.71,2.29 C0.55,2.29 0.39,2.28 0.23,2.26 C-0.4,2.17 -0.94,1.89 -1.41,1.42 C-1.89,0.94 -2.18,0.37 -2.26,-0.28 C-2.28,-0.42 -2.29,-0.56 -2.29,-0.71 C-2.29,-0.71 -2.31,-2.72 -2.31,-2.72 C-2.31,-2.72 -0.29,-0.71 -0.29,-0.71c "
+ android:valueTo="M-0.29 -0.71 C-0.29,-0.42 -0.19,-0.19 0,0.01 C0.19,0.2 0.43,0.29 0.71,0.29 C0.76,0.31 0.75,0.31 0.78,0.3 C1.14,0.67 1.92,1.43 2.34,1.85 C2.03,2.04 1.55,2.29 0.71,2.29 C0.55,2.29 0.39,2.28 0.23,2.26 C-0.4,2.17 -0.94,1.89 -1.41,1.42 C-1.89,0.94 -2.18,0.37 -2.26,-0.28 C-2.28,-0.42 -2.29,-0.56 -2.29,-0.71 C-2.29,-0.71 -2.31,-2.72 -2.31,-2.72 C-2.31,-2.72 -0.29,-0.71 -0.29,-0.71c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="pathData"
+ android:startOffset="67"
+ android:valueFrom="M-0.29 -0.71 C-0.29,-0.42 -0.19,-0.19 0,0.01 C0.19,0.2 0.43,0.29 0.71,0.29 C0.76,0.31 0.75,0.31 0.78,0.3 C1.14,0.67 1.92,1.43 2.34,1.85 C2.03,2.04 1.55,2.29 0.71,2.29 C0.55,2.29 0.39,2.28 0.23,2.26 C-0.4,2.17 -0.94,1.89 -1.41,1.42 C-1.89,0.94 -2.18,0.37 -2.26,-0.28 C-2.28,-0.42 -2.29,-0.56 -2.29,-0.71 C-2.29,-0.71 -2.31,-2.72 -2.31,-2.72 C-2.31,-2.72 -0.29,-0.71 -0.29,-0.71c "
+ android:valueTo="M-0.29 -0.71 C-0.29,-0.42 -0.19,-0.19 0,0.01 C0.19,0.2 0.43,0.29 0.71,0.29 C0.76,0.31 0.75,0.31 0.78,0.3 C1.14,0.67 1.92,1.43 2.34,1.85 C2.03,2.04 1.55,2.29 0.71,2.29 C0.55,2.29 0.39,2.28 0.23,2.26 C0.09,2.2 -0.55,1.45 -1.02,0.98 C-1.5,0.5 -2.23,-0.14 -2.26,-0.28 C-2.28,-0.42 -2.29,-0.56 -2.29,-0.71 C-2.29,-0.71 -2.31,-2.72 -2.31,-2.72 C-2.31,-2.72 -0.29,-0.71 -0.29,-0.71c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M-9.89 -7.81 C-9.89,-7.81 -9.9,-7.8 -9.9,-7.8 C-9.9,-7.8 -8.5,-9.2 -8.5,-9.2 C-8.5,-9.2 -8.49,-9.21 -8.49,-9.21 C-8.49,-9.21 -9.89,-7.81 -9.89,-7.81c "
+ android:valueTo="M8.5 10.6 C8.5,10.6 -9.9,-7.8 -9.9,-7.8 C-9.9,-7.8 -8.5,-9.2 -8.5,-9.2 C-8.5,-9.2 9.9,9.2 9.9,9.2 C9.9,9.2 8.5,10.6 8.5,10.6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="267"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="12"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M5.05 4.43 C3.98,5.25 3.08,5.53 2.53,5.73 C2.26,5.81 1.98,5.87 1.7,5.9 C1.7,5.9 1.7,9 1.7,9 C1.7,9 -0.3,9 -0.3,9 C-0.3,9 -0.3,5.9 -0.3,5.9 C-2.02,5.65 -3.44,4.88 -4.59,3.59 C-5.73,2.3 -6.3,0.77 -6.3,-1 C-6.3,-1 -4.3,-1 -4.3,-1 C-4.3,0.38 -3.81,1.56 -2.84,2.54 C-1.86,3.51 -0.68,4 0.7,4 C0.88,4 1.06,3.99 1.23,3.96 C1.39,3.94 2.58,3.77 3.61,2.99 C3.61,2.99 5.05,4.43 5.05,4.43c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M2.31 1.86 C2.31,1.86 1.01,0.55 0.75,0.31 C1.7,0.27 1.7,-0.7 1.7,-0.7 C1.7,-0.7 1.7,-7 1.7,-7 C1.7,-7.28 1.61,-7.52 1.41,-7.71 C1.22,-7.9 0.98,-8 0.7,-8 C0.42,-8 0.18,-7.9 -0.01,-7.71 C-0.2,-7.52 -0.3,-7.28 -0.3,-7 C-0.3,-7 -0.29,-0.66 -0.29,-0.66 C-0.29,-0.66 -2.31,-2.67 -2.31,-2.67 C-2.31,-2.67 -2.3,-7 -2.3,-7 C-2.3,-7.83 -2.01,-8.54 -1.42,-9.12 C-0.84,-9.71 -0.13,-10 0.7,-10 C1.53,-10 2.24,-9.71 2.83,-9.12 C3.41,-8.54 3.7,-7.83 3.7,-7 C3.7,-7 3.7,-1 3.7,-1 C3.7,-0.82 3.7,-0.33 3.64,-0.03 C3.51,0.52 3.23,1.19 2.31,1.86c " />
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M5.04 4.45 C5.04,4.45 3.59,3.02 3.59,3.02 C4.82,1.94 5.31,0.96 5.53,0.3 C5.64,-0.12 5.7,-0.55 5.7,-1 C5.7,-1 7.7,-1 7.7,-1 C7.7,-0.27 7.59,0.43 7.38,1.09 C7.16,1.75 6.51,3.17 5.04,4.45c " />
+ <path
+ android:name="_R_G_L_0_G_D_3_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M-0.29 -0.71 C-0.29,-0.42 -0.19,-0.19 0,0.01 C0.19,0.2 0.43,0.29 0.71,0.29 C0.76,0.31 0.75,0.31 0.78,0.3 C1.14,0.67 1.92,1.43 2.34,1.85 C2.03,2.04 1.55,2.29 0.71,2.29 C0.55,2.29 0.39,2.28 0.23,2.26 C-0.4,2.17 -0.94,1.89 -1.41,1.42 C-1.89,0.94 -2.18,0.37 -2.26,-0.28 C-2.28,-0.42 -2.29,-0.56 -2.29,-0.71 C-2.29,-0.71 -2.31,-2.72 -2.31,-2.72 C-2.31,-2.72 -0.29,-0.71 -0.29,-0.71c " />
+ <path
+ android:name="_R_G_L_0_G_D_4_P_0"
+ android:fillAlpha="0"
+ android:fillColor="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M-9.89 -7.81 C-9.89,-7.81 -9.9,-7.8 -9.9,-7.8 C-9.9,-7.8 -8.5,-9.2 -8.5,-9.2 C-8.5,-9.2 -8.49,-9.21 -8.49,-9.21 C-8.49,-9.21 -9.89,-7.81 -9.89,-7.81c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/qs_mic_access_on.xml b/packages/SystemUI/res/drawable/qs_mic_access_on.xml
new file mode 100644
index 0000000..b485f06
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_mic_access_on.xml
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M5.02 4.5 C3.59,5.47 2.79,5.64 2.53,5.73 C2.26,5.81 1.98,5.87 1.7,5.9 C1.7,5.9 1.7,9 1.7,9 C1.7,9 -0.3,9 -0.3,9 C-0.3,9 -0.3,5.9 -0.3,5.9 C-2.02,5.65 -3.44,4.88 -4.59,3.59 C-5.73,2.3 -6.3,0.77 -6.3,-1 C-6.3,-1 -4.3,-1 -4.3,-1 C-4.3,0.38 -3.81,1.56 -2.84,2.54 C-1.86,3.51 -0.68,4 0.7,4 C0.88,4 1.06,3.99 1.23,3.96 C1.39,3.94 2.53,3.83 3.58,3.07 C3.58,3.07 5.02,4.5 5.02,4.5c "
+ android:valueTo="M5.05 4.43 C3.98,5.25 3.08,5.53 2.53,5.73 C2.26,5.81 1.98,5.87 1.7,5.9 C1.7,5.9 1.7,9 1.7,9 C1.7,9 -0.3,9 -0.3,9 C-0.3,9 -0.3,5.9 -0.3,5.9 C-2.02,5.65 -3.44,4.88 -4.59,3.59 C-5.73,2.3 -6.3,0.77 -6.3,-1 C-6.3,-1 -4.3,-1 -4.3,-1 C-4.3,0.38 -3.81,1.56 -2.84,2.54 C-1.86,3.51 -0.68,4 0.7,4 C0.88,4 1.06,3.99 1.23,3.96 C1.39,3.94 2.58,3.77 3.61,2.99 C3.61,2.99 5.05,4.43 5.05,4.43c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="125"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M3.5 -0.05 C3.5,-0.05 1.7,-1.85 1.7,-1.85 C1.7,-1.85 1.7,-1.92 1.7,-1.92 C1.7,-1.92 1.7,-7 1.7,-7 C1.7,-7.28 1.61,-7.52 1.41,-7.71 C1.22,-7.9 0.98,-8 0.7,-8 C0.42,-8 0.18,-7.9 -0.01,-7.71 C-0.2,-7.52 -0.3,-7.28 -0.3,-7 C-0.3,-7 -0.3,-3.85 -0.3,-3.85 C-0.3,-3.85 -2.3,-5.85 -2.3,-5.85 C-2.3,-5.85 -2.3,-7 -2.3,-7 C-2.3,-7.83 -2.01,-8.54 -1.42,-9.12 C-0.84,-9.71 -0.13,-10 0.7,-10 C1.53,-10 2.24,-9.71 2.83,-9.12 C3.41,-8.54 3.7,-7.83 3.7,-7 C3.7,-7 3.7,-1 3.7,-1 C3.7,-0.82 3.68,-0.65 3.64,-0.5 C3.6,-0.35 3.55,-0.2 3.5,-0.05c "
+ android:valueTo="M3.12 0.99 C3.12,0.99 1.83,-0.26 1.71,-0.38 C1.72,-0.81 1.7,-1.31 1.7,-1.31 C1.7,-1.31 1.7,-7 1.7,-7 C1.7,-7.28 1.61,-7.52 1.41,-7.71 C1.22,-7.9 0.98,-8 0.7,-8 C0.42,-8 0.18,-7.9 -0.01,-7.71 C-0.2,-7.52 -0.3,-7.28 -0.3,-7 C-0.3,-7 -0.29,-2.26 -0.29,-2.26 C-0.29,-2.26 -2.31,-4.23 -2.31,-4.23 C-2.31,-4.23 -2.3,-7 -2.3,-7 C-2.3,-7.83 -2.01,-8.54 -1.42,-9.12 C-0.84,-9.71 -0.13,-10 0.7,-10 C1.53,-10 2.24,-9.71 2.83,-9.12 C3.41,-8.54 3.7,-7.83 3.7,-7 C3.7,-7 3.7,-1 3.7,-1 C3.7,-0.82 3.67,-0.54 3.66,-0.3 C3.63,0.12 3.38,0.7 3.12,0.99c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="58"
+ android:propertyName="pathData"
+ android:startOffset="125"
+ android:valueFrom="M3.12 0.99 C3.12,0.99 1.83,-0.26 1.71,-0.38 C1.72,-0.81 1.7,-1.31 1.7,-1.31 C1.7,-1.31 1.7,-7 1.7,-7 C1.7,-7.28 1.61,-7.52 1.41,-7.71 C1.22,-7.9 0.98,-8 0.7,-8 C0.42,-8 0.18,-7.9 -0.01,-7.71 C-0.2,-7.52 -0.3,-7.28 -0.3,-7 C-0.3,-7 -0.29,-2.26 -0.29,-2.26 C-0.29,-2.26 -2.31,-4.23 -2.31,-4.23 C-2.31,-4.23 -2.3,-7 -2.3,-7 C-2.3,-7.83 -2.01,-8.54 -1.42,-9.12 C-0.84,-9.71 -0.13,-10 0.7,-10 C1.53,-10 2.24,-9.71 2.83,-9.12 C3.41,-8.54 3.7,-7.83 3.7,-7 C3.7,-7 3.7,-1 3.7,-1 C3.7,-0.82 3.67,-0.54 3.66,-0.3 C3.63,0.12 3.38,0.7 3.12,0.99c "
+ android:valueTo="M2.86 1.48 C2.86,1.48 1.58,0.21 1.39,0.03 C1.77,-0.26 1.7,-1.03 1.7,-1.03 C1.7,-1.03 1.7,-7 1.7,-7 C1.7,-7.28 1.61,-7.52 1.41,-7.71 C1.22,-7.9 0.98,-8 0.7,-8 C0.42,-8 0.18,-7.9 -0.01,-7.71 C-0.2,-7.52 -0.3,-7.28 -0.3,-7 C-0.3,-7 -0.29,-1.51 -0.29,-1.51 C-0.29,-1.51 -2.31,-3.5 -2.31,-3.5 C-2.31,-3.5 -2.3,-7 -2.3,-7 C-2.3,-7.83 -2.01,-8.54 -1.42,-9.12 C-0.84,-9.71 -0.13,-10 0.7,-10 C1.53,-10 2.24,-9.71 2.83,-9.12 C3.41,-8.54 3.7,-7.83 3.7,-7 C3.7,-7 3.7,-1 3.7,-1 C3.7,-0.82 3.68,-0.44 3.65,-0.17 C3.61,0.19 3.36,1.05 2.86,1.48c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="pathData"
+ android:startOffset="183"
+ android:valueFrom="M2.86 1.48 C2.86,1.48 1.58,0.21 1.39,0.03 C1.77,-0.26 1.7,-1.03 1.7,-1.03 C1.7,-1.03 1.7,-7 1.7,-7 C1.7,-7.28 1.61,-7.52 1.41,-7.71 C1.22,-7.9 0.98,-8 0.7,-8 C0.42,-8 0.18,-7.9 -0.01,-7.71 C-0.2,-7.52 -0.3,-7.28 -0.3,-7 C-0.3,-7 -0.29,-1.51 -0.29,-1.51 C-0.29,-1.51 -2.31,-3.5 -2.31,-3.5 C-2.31,-3.5 -2.3,-7 -2.3,-7 C-2.3,-7.83 -2.01,-8.54 -1.42,-9.12 C-0.84,-9.71 -0.13,-10 0.7,-10 C1.53,-10 2.24,-9.71 2.83,-9.12 C3.41,-8.54 3.7,-7.83 3.7,-7 C3.7,-7 3.7,-1 3.7,-1 C3.7,-0.82 3.68,-0.44 3.65,-0.17 C3.61,0.19 3.36,1.05 2.86,1.48c "
+ android:valueTo="M2.42 1.81 C2.42,1.81 1.16,0.52 0.9,0.28 C1.7,0.14 1.7,-0.7 1.7,-0.7 C1.7,-0.7 1.7,-7 1.7,-7 C1.7,-7.28 1.61,-7.52 1.41,-7.71 C1.22,-7.9 0.98,-8 0.7,-8 C0.42,-8 0.18,-7.9 -0.01,-7.71 C-0.2,-7.52 -0.3,-7.28 -0.3,-7 C-0.3,-7 -0.29,-0.66 -0.29,-0.66 C-0.29,-0.66 -2.31,-2.67 -2.31,-2.67 C-2.31,-2.67 -2.3,-7 -2.3,-7 C-2.3,-7.83 -2.01,-8.54 -1.42,-9.12 C-0.84,-9.71 -0.13,-10 0.7,-10 C1.53,-10 2.24,-9.71 2.83,-9.12 C3.41,-8.54 3.7,-7.83 3.7,-7 C3.7,-7 3.7,-1 3.7,-1 C3.7,-0.82 3.7,-0.33 3.64,-0.03 C3.58,0.27 3.22,1.2 2.42,1.81c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M6.45 2.95 C6.45,2.95 5,1.5 5,1.5 C5.23,1.12 5.41,0.72 5.53,0.3 C5.64,-0.12 5.7,-0.55 5.7,-1 C5.7,-1 7.7,-1 7.7,-1 C7.7,-0.27 7.59,0.43 7.38,1.09 C7.16,1.75 6.85,2.37 6.45,2.95c "
+ android:valueTo="M5.04 4.43 C5.04,4.43 3.59,2.98 3.59,2.98 C4.61,2.09 5.41,0.72 5.53,0.3 C5.64,-0.12 5.7,-0.55 5.7,-1 C5.7,-1 7.7,-1 7.7,-1 C7.7,-0.27 7.59,0.43 7.38,1.09 C7.16,1.75 6.19,3.44 5.04,4.43c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M-0.29 -0.71 C-0.29,-0.42 -0.19,-0.19 0,0.01 C0.19,0.2 0.43,0.29 0.71,0.29 C0.76,0.31 0.75,0.31 0.78,0.3 C1.14,0.67 1.92,1.43 2.34,1.85 C2.03,2.04 1.55,2.29 0.71,2.29 C0.55,2.29 0.39,2.28 0.23,2.26 C0.09,2.2 -0.55,1.45 -1.02,0.98 C-1.5,0.5 -2.23,-0.14 -2.26,-0.28 C-2.28,-0.42 -2.29,-0.56 -2.29,-0.71 C-2.29,-0.71 -2.31,-2.72 -2.31,-2.72 C-2.31,-2.72 -0.29,-0.71 -0.29,-0.71c "
+ android:valueTo="M-0.29 -0.71 C-0.29,-0.42 -0.19,-0.19 0,0.01 C0.19,0.2 0.43,0.29 0.71,0.29 C0.76,0.31 0.75,0.31 0.78,0.3 C1.14,0.67 1.92,1.43 2.34,1.85 C2.03,2.04 1.55,2.29 0.71,2.29 C0.55,2.29 0.39,2.28 0.23,2.26 C-0.4,2.17 -0.94,1.89 -1.41,1.42 C-1.89,0.94 -2.18,0.37 -2.26,-0.28 C-2.28,-0.42 -2.29,-0.56 -2.29,-0.71 C-2.29,-0.71 -2.31,-2.72 -2.31,-2.72 C-2.31,-2.72 -0.29,-0.71 -0.29,-0.71c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.1,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="400"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="400"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M8.5 10.6 C8.5,10.6 -9.9,-7.8 -9.9,-7.8 C-9.9,-7.8 -8.5,-9.2 -8.5,-9.2 C-8.5,-9.2 9.9,9.2 9.9,9.2 C9.9,9.2 8.5,10.6 8.5,10.6c "
+ android:valueTo="M8.5 10.6 C8.5,10.6 8.51,10.6 8.51,10.6 C8.51,10.6 9.91,9.2 9.91,9.2 C9.91,9.2 9.9,9.2 9.9,9.2 C9.9,9.2 8.5,10.6 8.5,10.6c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.5,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="433"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="12"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M5.02 4.5 C3.59,5.47 2.79,5.64 2.53,5.73 C2.26,5.81 1.98,5.87 1.7,5.9 C1.7,5.9 1.7,9 1.7,9 C1.7,9 -0.3,9 -0.3,9 C-0.3,9 -0.3,5.9 -0.3,5.9 C-2.02,5.65 -3.44,4.88 -4.59,3.59 C-5.73,2.3 -6.3,0.77 -6.3,-1 C-6.3,-1 -4.3,-1 -4.3,-1 C-4.3,0.38 -3.81,1.56 -2.84,2.54 C-1.86,3.51 -0.68,4 0.7,4 C0.88,4 1.06,3.99 1.23,3.96 C1.39,3.94 2.53,3.83 3.58,3.07 C3.58,3.07 5.02,4.5 5.02,4.5c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M3.5 -0.05 C3.5,-0.05 1.7,-1.85 1.7,-1.85 C1.7,-1.85 1.7,-1.92 1.7,-1.92 C1.7,-1.92 1.7,-7 1.7,-7 C1.7,-7.28 1.61,-7.52 1.41,-7.71 C1.22,-7.9 0.98,-8 0.7,-8 C0.42,-8 0.18,-7.9 -0.01,-7.71 C-0.2,-7.52 -0.3,-7.28 -0.3,-7 C-0.3,-7 -0.3,-3.85 -0.3,-3.85 C-0.3,-3.85 -2.3,-5.85 -2.3,-5.85 C-2.3,-5.85 -2.3,-7 -2.3,-7 C-2.3,-7.83 -2.01,-8.54 -1.42,-9.12 C-0.84,-9.71 -0.13,-10 0.7,-10 C1.53,-10 2.24,-9.71 2.83,-9.12 C3.41,-8.54 3.7,-7.83 3.7,-7 C3.7,-7 3.7,-1 3.7,-1 C3.7,-0.82 3.68,-0.65 3.64,-0.5 C3.6,-0.35 3.55,-0.2 3.5,-0.05c " />
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M6.45 2.95 C6.45,2.95 5,1.5 5,1.5 C5.23,1.12 5.41,0.72 5.53,0.3 C5.64,-0.12 5.7,-0.55 5.7,-1 C5.7,-1 7.7,-1 7.7,-1 C7.7,-0.27 7.59,0.43 7.38,1.09 C7.16,1.75 6.85,2.37 6.45,2.95c " />
+ <path
+ android:name="_R_G_L_0_G_D_3_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-0.29 -0.71 C-0.29,-0.42 -0.19,-0.19 0,0.01 C0.19,0.2 0.43,0.29 0.71,0.29 C0.76,0.31 0.75,0.31 0.78,0.3 C1.14,0.67 1.92,1.43 2.34,1.85 C2.03,2.04 1.55,2.29 0.71,2.29 C0.55,2.29 0.39,2.28 0.23,2.26 C0.09,2.2 -0.55,1.45 -1.02,0.98 C-1.5,0.5 -2.23,-0.14 -2.26,-0.28 C-2.28,-0.42 -2.29,-0.56 -2.29,-0.71 C-2.29,-0.71 -2.31,-2.72 -2.31,-2.72 C-2.31,-2.72 -0.29,-0.71 -0.29,-0.71c " />
+ <path
+ android:name="_R_G_L_0_G_D_4_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M8.5 10.6 C8.5,10.6 -9.9,-7.8 -9.9,-7.8 C-9.9,-7.8 -8.5,-9.2 -8.5,-9.2 C-8.5,-9.2 9.9,9.2 9.9,9.2 C9.9,9.2 8.5,10.6 8.5,10.6c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/screenshot_edit_background.xml b/packages/SystemUI/res/drawable/screenshot_edit_background.xml
index ff5c62e..a1185a2 100644
--- a/packages/SystemUI/res/drawable/screenshot_edit_background.xml
+++ b/packages/SystemUI/res/drawable/screenshot_edit_background.xml
@@ -17,7 +17,7 @@
<!-- Long screenshot edit FAB background -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:color="?android:textColorPrimary">
+ android:color="@color/overlay_button_ripple">
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<solid android:color="?androidprv:attr/colorAccentPrimary"/>
diff --git a/packages/SystemUI/res/layout/brightness_mirror_container.xml b/packages/SystemUI/res/layout/brightness_mirror_container.xml
index ac90db3..1bf45aa 100644
--- a/packages/SystemUI/res/layout/brightness_mirror_container.xml
+++ b/packages/SystemUI/res/layout/brightness_mirror_container.xml
@@ -23,7 +23,6 @@
android:background="@drawable/brightness_mirror_background"
android:layout_gravity="center_vertical"
android:layout_margin="8dp"
- android:padding="@dimen/rounded_slider_background_padding"
android:gravity="center"
android:visibility="invisible">
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index 1efb479..eb43853 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -89,8 +89,7 @@
android:id="@+id/list_result"
android:scrollbars="vertical"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:overScrollMode="never"/>
+ android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
diff --git a/packages/SystemUI/screenshot/Android.bp b/packages/SystemUI/screenshot/Android.bp
index a79fd9040d..601e92f 100644
--- a/packages/SystemUI/screenshot/Android.bp
+++ b/packages/SystemUI/screenshot/Android.bp
@@ -26,11 +26,7 @@
manifest: "AndroidManifest.xml",
srcs: [
- // All files in this library should be in Kotlin besides some exceptions.
"src/**/*.kt",
-
- // This file was forked from google3, so exceptionally it can be in Java.
- "src/com/android/systemui/testing/screenshot/DynamicColorsTestUtils.java",
],
resource_dirs: [
diff --git a/packages/SystemUI/screenshot/AndroidManifest.xml b/packages/SystemUI/screenshot/AndroidManifest.xml
index 3b703be..a405836 100644
--- a/packages/SystemUI/screenshot/AndroidManifest.xml
+++ b/packages/SystemUI/screenshot/AndroidManifest.xml
@@ -23,6 +23,4 @@
android:exported="true"
android:theme="@style/Theme.SystemUI.Screenshot" />
</application>
-
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
</manifest>
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/Bitmap.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/Bitmap.kt
new file mode 100644
index 0000000..3d26cda
--- /dev/null
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/Bitmap.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.testing.screenshot
+
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.os.Build
+import android.view.View
+import platform.test.screenshot.matchers.MSSIMMatcher
+import platform.test.screenshot.matchers.PixelPerfectMatcher
+
+/** Draw this [View] into a [Bitmap]. */
+fun View.drawIntoBitmap(): Bitmap {
+ val bitmap =
+ Bitmap.createBitmap(
+ measuredWidth,
+ measuredHeight,
+ Bitmap.Config.ARGB_8888,
+ )
+ val canvas = Canvas(bitmap)
+ draw(canvas)
+ return bitmap
+}
+
+/**
+ * The [BitmapMatcher][platform.test.screenshot.matchers.BitmapMatcher] that should be used for
+ * screenshot *unit* tests.
+ */
+val UnitTestBitmapMatcher =
+ if (Build.CPU_ABI == "x86_64") {
+ // Different CPU architectures can sometimes end up rendering differently, so we can't do
+ // pixel-perfect matching on different architectures using the same golden. Given that our
+ // presubmits are run on cf_x86_64_phone, our goldens should be perfectly matched on the
+ // x86_64 architecture and use the Structural Similarity Index on others.
+ // TODO(b/237511747): Run our screenshot presubmit tests on arm64 instead so that we can
+ // do pixel perfect matching both at presubmit time and at development time with actual
+ // devices.
+ PixelPerfectMatcher()
+ } else {
+ MSSIMMatcher()
+ }
+
+/**
+ * The [BitmapMatcher][platform.test.screenshot.matchers.BitmapMatcher] that should be used for
+ * screenshot *unit* tests.
+ *
+ * We use the Structural Similarity Index for integration tests because they usually contain
+ * additional information and noise that shouldn't break the test.
+ */
+val IntegrationTestBitmapMatcher = MSSIMMatcher()
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/DynamicColorsTestUtils.java b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/DynamicColorsTestUtils.java
deleted file mode 100644
index 96ec4c5..0000000
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/DynamicColorsTestUtils.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.testing.screenshot;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import android.app.UiAutomation;
-import android.content.Context;
-import android.provider.Settings;
-import android.util.Log;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.ColorRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
-import androidx.core.content.ContextCompat;
-import androidx.test.espresso.Espresso;
-import androidx.test.espresso.IdlingRegistry;
-import androidx.test.espresso.IdlingResource;
-
-import org.json.JSONObject;
-import org.junit.function.ThrowingRunnable;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/*
- * Note: This file was forked from
- * google3/third_party/java_src/android_libs/material_components/screenshot_tests/java/android/
- * support/design/scuba/color/DynamicColorsTestUtils.java.
- */
-
-/** Utility that helps change the dynamic system colors for testing. */
-@RequiresApi(32)
-public class DynamicColorsTestUtils {
-
- private static final String TAG = DynamicColorsTestUtils.class.getSimpleName();
-
- private static final String THEME_CUSTOMIZATION_KEY = "theme_customization_overlay_packages";
- private static final String THEME_CUSTOMIZATION_SYSTEM_PALETTE_KEY =
- "android.theme.customization.system_palette";
-
- private static final int ORANGE_SYSTEM_SEED_COLOR = 0xA66800;
- private static final int ORANGE_EXPECTED_SYSTEM_ACCENT1_600_COLOR = -8235756;
-
- private DynamicColorsTestUtils() {
- }
-
- /**
- * Update system dynamic colors (e.g., android.R.color.system_accent1_600) based on an orange
- * seed color, and then wait for the change to propagate to the app by comparing
- * android.R.color.system_accent1_600 to the expected orange value.
- */
- public static void updateSystemColorsToOrange() {
- updateSystemColors(ORANGE_SYSTEM_SEED_COLOR, ORANGE_EXPECTED_SYSTEM_ACCENT1_600_COLOR);
- }
-
- /**
- * Update system dynamic colors (e.g., android.R.color.system_accent1_600) based on the provided
- * {@code seedColor}, and then wait for the change to propagate to the app by comparing
- * android.R.color.system_accent1_600 to {@code expectedSystemAccent1600}.
- */
- public static void updateSystemColors(
- @ColorInt int seedColor, @ColorInt int expectedSystemAccent1600) {
- Context context = getInstrumentation().getTargetContext();
-
- int actualSystemAccent1600 =
- ContextCompat.getColor(context, android.R.color.system_accent1_600);
-
- if (expectedSystemAccent1600 == actualSystemAccent1600) {
- String expectedColorString = Integer.toHexString(expectedSystemAccent1600);
- Log.d(
- TAG,
- "Skipped updating system colors since system_accent1_600 is already equal to "
- + "expected: "
- + expectedColorString);
- return;
- }
-
- updateSystemColors(seedColor);
- }
-
- /**
- * Update system dynamic colors (e.g., android.R.color.system_accent1_600) based on the provided
- * {@code seedColor}, and then wait for the change to propagate to the app by checking
- * android.R.color.system_accent1_600 for any change.
- */
- public static void updateSystemColors(@ColorInt int seedColor) {
- Context context = getInstrumentation().getTargetContext();
-
- // Initialize system color idling resource with original system_accent1_600 value.
- ColorChangeIdlingResource systemColorIdlingResource =
- new ColorChangeIdlingResource(context, android.R.color.system_accent1_600);
-
- // Update system theme color setting to trigger fabricated resource overlay.
- runWithShellPermissionIdentity(
- () ->
- Settings.Secure.putString(
- context.getContentResolver(),
- THEME_CUSTOMIZATION_KEY,
- buildThemeCustomizationString(seedColor)));
-
- // Wait for system color update to propagate to app.
- IdlingRegistry idlingRegistry = IdlingRegistry.getInstance();
- idlingRegistry.register(systemColorIdlingResource);
- Espresso.onIdle();
- idlingRegistry.unregister(systemColorIdlingResource);
-
- Log.d(TAG,
- Settings.Secure.getString(context.getContentResolver(), THEME_CUSTOMIZATION_KEY));
- }
-
- private static String buildThemeCustomizationString(@ColorInt int seedColor) {
- String seedColorHex = Integer.toHexString(seedColor);
- Map<String, String> themeCustomizationMap = new HashMap<>();
- themeCustomizationMap.put(THEME_CUSTOMIZATION_SYSTEM_PALETTE_KEY, seedColorHex);
- return new JSONObject(themeCustomizationMap).toString();
- }
-
- private static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable runnable) {
- UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
- uiAutomation.adoptShellPermissionIdentity();
- try {
- runnable.run();
- } catch (Throwable e) {
- throw new RuntimeException(e);
- } finally {
- uiAutomation.dropShellPermissionIdentity();
- }
- }
-
- private static class ColorChangeIdlingResource implements IdlingResource {
-
- private final Context mContext;
- private final int mColorResId;
- private final int mInitialColorInt;
-
- private ResourceCallback mResourceCallback;
- private boolean mIdleNow;
-
- ColorChangeIdlingResource(Context context, @ColorRes int colorResId) {
- this.mContext = context;
- this.mColorResId = colorResId;
- this.mInitialColorInt = ContextCompat.getColor(context, colorResId);
- }
-
- @Override
- public String getName() {
- return ColorChangeIdlingResource.class.getName();
- }
-
- @Override
- public boolean isIdleNow() {
- if (mIdleNow) {
- return true;
- }
-
- int currentColorInt = ContextCompat.getColor(mContext, mColorResId);
-
- String initialColorString = Integer.toHexString(mInitialColorInt);
- String currentColorString = Integer.toHexString(currentColorInt);
- Log.d(TAG, String.format("Initial=%s, Current=%s", initialColorString,
- currentColorString));
-
- mIdleNow = currentColorInt != mInitialColorInt;
- Log.d(TAG, String.format("idleNow=%b", mIdleNow));
-
- if (mIdleNow) {
- mResourceCallback.onTransitionToIdle();
- }
- return mIdleNow;
- }
-
- @Override
- public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
- this.mResourceCallback = resourceCallback;
- }
- }
-}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ScreenshotTestRule.kt
deleted file mode 100644
index 564901c..0000000
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ScreenshotTestRule.kt
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.testing.screenshot
-
-import android.app.UiModeManager
-import android.content.Context
-import android.graphics.Bitmap
-import android.graphics.Canvas
-import android.os.Build
-import android.os.UserHandle
-import android.view.Display
-import android.view.View
-import android.view.WindowManagerGlobal
-import androidx.test.platform.app.InstrumentationRegistry
-import org.junit.rules.TestRule
-import org.junit.runner.Description
-import org.junit.runners.model.Statement
-import platform.test.screenshot.GoldenImagePathManager
-import platform.test.screenshot.PathConfig
-import platform.test.screenshot.PathElementNoContext
-import platform.test.screenshot.ScreenshotTestRule
-import platform.test.screenshot.matchers.MSSIMMatcher
-import platform.test.screenshot.matchers.PixelPerfectMatcher
-
-/**
- * A base rule for screenshot diff tests.
- *
- * This rules takes care of setting up the activity according to [testSpec] by:
- * - emulating the display size and density.
- * - setting the dark/light mode.
- * - setting the system (Material You) colors to a fixed value.
- *
- * @see ComposeScreenshotTestRule
- * @see ViewScreenshotTestRule
- */
-class ScreenshotTestRule(private val testSpec: ScreenshotTestSpec) : TestRule {
- private var currentDisplay: DisplaySpec? = null
- private var currentGoldenIdentifier: String? = null
-
- private val pathConfig =
- PathConfig(
- PathElementNoContext("model", isDir = true) {
- currentDisplay?.name ?: error("currentDisplay is null")
- },
- )
- private val matcher = if (shouldUsePerfectMatching()) {
- PixelPerfectMatcher()
- } else {
- MSSIMMatcher()
- }
-
- private val screenshotRule =
- ScreenshotTestRule(
- SystemUIGoldenImagePathManager(
- pathConfig,
- currentGoldenIdentifier = {
- currentGoldenIdentifier ?: error("currentGoldenIdentifier is null")
- },
- )
- )
-
- private fun shouldUsePerfectMatching(): Boolean {
- // Different CPU architectures can sometimes end up rendering differently, so we can't do
- // pixel-perfect matching on different architectures using the same golden. Given that our
- // presubmits are run on cf_x86_64_phone, our goldens should be perfectly matched on the
- // x86_64 architecture and use the Structural Similarity Index on others.
- // TODO(b/237511747): Run our screenshot presubmit tests on arm64 instead so that we can
- // do pixel perfect matching both at presubmit time and at development time with actual
- // devices.
- return Build.CPU_ABI == "x86_64"
- }
-
- override fun apply(base: Statement, description: Description): Statement {
- // The statement which call beforeTest() before running the test and afterTest() afterwards.
- val statement =
- object : Statement() {
- override fun evaluate() {
- try {
- beforeTest()
- base.evaluate()
- } finally {
- afterTest()
- }
- }
- }
-
- return screenshotRule.apply(statement, description)
- }
-
- private fun beforeTest() {
- // Update the system colors to a fixed color, so that tests don't depend on the host device
- // extracted colors. Note that we don't restore the default device colors at the end of the
- // test because changing the colors (and waiting for them to be applied) is costly and makes
- // the screenshot tests noticeably slower.
- DynamicColorsTestUtils.updateSystemColorsToOrange()
-
- // Emulate the display size and density.
- val display = testSpec.display
- val density = display.densityDpi
- val wm = WindowManagerGlobal.getWindowManagerService()
- val (width, height) = getEmulatedDisplaySize()
- wm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, density, UserHandle.myUserId())
- wm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, width, height)
-
- // Force the dark/light theme.
- val uiModeManager =
- InstrumentationRegistry.getInstrumentation()
- .targetContext
- .getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
- uiModeManager.setApplicationNightMode(
- if (testSpec.isDarkTheme) {
- UiModeManager.MODE_NIGHT_YES
- } else {
- UiModeManager.MODE_NIGHT_NO
- }
- )
- }
-
- private fun afterTest() {
- // Reset the density and display size.
- val wm = WindowManagerGlobal.getWindowManagerService()
- wm.clearForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, UserHandle.myUserId())
- wm.clearForcedDisplaySize(Display.DEFAULT_DISPLAY)
-
- // Reset the dark/light theme.
- val uiModeManager =
- InstrumentationRegistry.getInstrumentation()
- .targetContext
- .getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
- uiModeManager.setApplicationNightMode(UiModeManager.MODE_NIGHT_AUTO)
- }
-
- /**
- * Compare the content of [view] with the golden image identified by [goldenIdentifier] in the
- * context of [testSpec].
- */
- fun screenshotTest(goldenIdentifier: String, view: View) {
- val bitmap = drawIntoBitmap(view)
-
- // Compare bitmap against golden asset.
- val isDarkTheme = testSpec.isDarkTheme
- val isLandscape = testSpec.isLandscape
- val identifierWithSpec = buildString {
- append(goldenIdentifier)
- if (isDarkTheme) append("_dark")
- if (isLandscape) append("_landscape")
- }
-
- // TODO(b/230832101): Provide a way to pass a PathConfig and override the file name on
- // device to assertBitmapAgainstGolden instead?
- currentDisplay = testSpec.display
- currentGoldenIdentifier = goldenIdentifier
- screenshotRule.assertBitmapAgainstGolden(bitmap, identifierWithSpec, matcher)
- currentDisplay = null
- currentGoldenIdentifier = goldenIdentifier
- }
-
- /** Draw [view] into a [Bitmap]. */
- private fun drawIntoBitmap(view: View): Bitmap {
- val bitmap =
- Bitmap.createBitmap(
- view.measuredWidth,
- view.measuredHeight,
- Bitmap.Config.ARGB_8888,
- )
- val canvas = Canvas(bitmap)
- view.draw(canvas)
- return bitmap
- }
-
- /** Get the emulated display size for [testSpec]. */
- private fun getEmulatedDisplaySize(): Pair<Int, Int> {
- val display = testSpec.display
- val isPortraitNaturalPosition = display.width < display.height
- return if (testSpec.isLandscape) {
- if (isPortraitNaturalPosition) {
- display.height to display.width
- } else {
- display.width to display.height
- }
- } else {
- if (isPortraitNaturalPosition) {
- display.width to display.height
- } else {
- display.height to display.width
- }
- }
- }
-}
-
-private class SystemUIGoldenImagePathManager(
- pathConfig: PathConfig,
- private val currentGoldenIdentifier: () -> String,
-) :
- GoldenImagePathManager(
- appContext = InstrumentationRegistry.getInstrumentation().context,
- deviceLocalPath =
- InstrumentationRegistry.getInstrumentation()
- .targetContext
- .filesDir
- .absolutePath
- .toString() + "/sysui_screenshots",
- pathConfig = pathConfig,
- ) {
- // This string is appended to all actual/expected screenshots on the device. We append the
- // golden identifier so that our pull_golden.py scripts can map a screenshot on device to its
- // asset (and automatically update it, if necessary).
- override fun toString() = currentGoldenIdentifier()
-}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ScreenshotTestSpec.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ScreenshotTestSpec.kt
deleted file mode 100644
index 7fc6245..0000000
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ScreenshotTestSpec.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.testing.screenshot
-
-/** The specification of a device display to be used in a screenshot test. */
-data class DisplaySpec(
- val name: String,
- val width: Int,
- val height: Int,
- val densityDpi: Int,
-)
-
-/** The specification of a screenshot diff test. */
-class ScreenshotTestSpec(
- val display: DisplaySpec,
- val isDarkTheme: Boolean = false,
- val isLandscape: Boolean = false,
-) {
- companion object {
- /**
- * Return a list of [ScreenshotTestSpec] for each of the [displays].
- *
- * If [isDarkTheme] is null, this will create a spec for both light and dark themes, for
- * each of the orientation.
- *
- * If [isLandscape] is null, this will create a spec for both portrait and landscape, for
- * each of the light/dark themes.
- */
- fun forDisplays(
- vararg displays: DisplaySpec,
- isDarkTheme: Boolean? = null,
- isLandscape: Boolean? = null,
- ): List<ScreenshotTestSpec> {
- return displays.flatMap { display ->
- buildList {
- fun addDisplay(isLandscape: Boolean) {
- if (isDarkTheme != true) {
- add(ScreenshotTestSpec(display, isDarkTheme = false, isLandscape))
- }
-
- if (isDarkTheme != false) {
- add(ScreenshotTestSpec(display, isDarkTheme = true, isLandscape))
- }
- }
-
- if (isLandscape != true) {
- addDisplay(isLandscape = false)
- }
-
- if (isLandscape != false) {
- addDisplay(isLandscape = true)
- }
- }
- }
- }
- }
-
- override fun toString(): String = buildString {
- // This string is appended to PNGs stored in the device, so let's keep it simple.
- append(display.name)
- if (isDarkTheme) append("_dark")
- if (isLandscape) append("_landscape")
- }
-}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/SystemUIGoldenImagePathManager.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/SystemUIGoldenImagePathManager.kt
new file mode 100644
index 0000000..cbab0a7
--- /dev/null
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/SystemUIGoldenImagePathManager.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.testing.screenshot
+
+import androidx.test.platform.app.InstrumentationRegistry
+import platform.test.screenshot.GoldenImagePathManager
+import platform.test.screenshot.PathConfig
+
+/** A [GoldenImagePathManager] that should be used for all SystemUI screenshot tests. */
+class SystemUIGoldenImagePathManager(
+ pathConfig: PathConfig,
+) :
+ GoldenImagePathManager(
+ appContext = InstrumentationRegistry.getInstrumentation().context,
+ deviceLocalPath =
+ InstrumentationRegistry.getInstrumentation()
+ .targetContext
+ .filesDir
+ .absolutePath
+ .toString() + "/sysui_screenshots",
+ pathConfig = pathConfig,
+ ) {
+ override fun toString(): String {
+ // This string is appended to all actual/expected screenshots on the device, so make sure
+ // it is a static value.
+ return "SystemUIGoldenImagePathManager"
+ }
+}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
index 6a80c48..3209c8b 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.systemui.testing.screenshot
import android.app.Activity
@@ -11,21 +27,35 @@
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
+import platform.test.screenshot.DeviceEmulationRule
+import platform.test.screenshot.DeviceEmulationSpec
+import platform.test.screenshot.MaterialYouColorsRule
+import platform.test.screenshot.ScreenshotTestRule
+import platform.test.screenshot.getEmulatedDevicePathConfig
-/** A rule for View screenshot diff tests. */
-class ViewScreenshotTestRule(testSpec: ScreenshotTestSpec) : TestRule {
+/** A rule for View screenshot diff unit tests. */
+class ViewScreenshotTestRule(emulationSpec: DeviceEmulationSpec) : TestRule {
+ private val colorsRule = MaterialYouColorsRule()
+ private val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
+ private val screenshotRule =
+ ScreenshotTestRule(
+ SystemUIGoldenImagePathManager(getEmulatedDevicePathConfig(emulationSpec))
+ )
private val activityRule = ActivityScenarioRule(ScreenshotActivity::class.java)
- private val screenshotRule = ScreenshotTestRule(testSpec)
-
- private val delegate = RuleChain.outerRule(screenshotRule).around(activityRule)
+ private val delegateRule =
+ RuleChain.outerRule(colorsRule)
+ .around(deviceEmulationRule)
+ .around(screenshotRule)
+ .around(activityRule)
+ private val matcher = UnitTestBitmapMatcher
override fun apply(base: Statement, description: Description): Statement {
- return delegate.apply(base, description)
+ return delegateRule.apply(base, description)
}
/**
* Compare the content of the view provided by [viewProvider] with the golden image identified
- * by [goldenIdentifier] in the context of [testSpec].
+ * by [goldenIdentifier] in the context of [emulationSpec].
*/
fun screenshotTest(
goldenIdentifier: String,
@@ -46,13 +76,17 @@
// Check that the content is what we expected.
val content = activity.requireViewById<ViewGroup>(android.R.id.content)
assertEquals(1, content.childCount)
- screenshotRule.screenshotTest(goldenIdentifier, content.getChildAt(0))
+ screenshotRule.assertBitmapAgainstGolden(
+ content.getChildAt(0).drawIntoBitmap(),
+ goldenIdentifier,
+ matcher
+ )
}
}
/**
* Compare the content of the dialog provided by [dialogProvider] with the golden image
- * identified by [goldenIdentifier] in the context of [testSpec].
+ * identified by [goldenIdentifier] in the context of [emulationSpec].
*/
fun dialogScreenshotTest(
goldenIdentifier: String,
@@ -81,7 +115,11 @@
// Check that the content is what we expected.
val dialog = dialog ?: error("dialog is null")
try {
- screenshotRule.screenshotTest(goldenIdentifier, dialog.window.decorView)
+ screenshotRule.assertBitmapAgainstGolden(
+ dialog.window.decorView.drawIntoBitmap(),
+ goldenIdentifier,
+ matcher,
+ )
} finally {
dialog.dismiss()
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 2dade21..b05582e 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -18,7 +18,6 @@
import android.app.ActivityThread;
import android.content.Context;
-import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Handler;
import android.os.HandlerThread;
@@ -29,7 +28,6 @@
import com.android.systemui.dagger.GlobalRootComponent;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.WMComponent;
-import com.android.systemui.navigationbar.gestural.BackGestureTfClassifierProvider;
import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider;
import com.android.wm.shell.dagger.WMShellConcurrencyModule;
import com.android.wm.shell.transition.ShellTransitions;
@@ -251,13 +249,4 @@
Context context, Executor executor, Handler uiHandler) {
return new ScreenshotNotificationSmartActionsProvider();
}
-
- /**
- * Creates an instance of BackGestureTfClassifierProvider.
- * This method is overridden in vendor specific implementation of Sys UI.
- */
- public BackGestureTfClassifierProvider createBackGestureTfClassifierProvider(
- AssetManager am, String modelName) {
- return new BackGestureTfClassifierProvider();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
index 3f78f97..1fa9ac5 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
@@ -74,6 +74,7 @@
}
mEditText.setText(clip.getItemAt(0).getText());
mEditText.requestFocus();
+ mEditText.setSelection(0);
mSensitive = clip.getDescription().getExtras() != null
&& clip.getDescription().getExtras()
.getBoolean(ClipDescription.EXTRA_IS_SENSITIVE);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index afc58ef..4096ed4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -42,6 +42,7 @@
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutManager;
+import android.content.res.AssetManager;
import android.content.res.Resources;
import android.hardware.SensorManager;
import android.hardware.SensorPrivacyManager;
@@ -91,6 +92,7 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.LatencyTracker;
import com.android.systemui.Prefs;
+import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.TestHarness;
@@ -405,6 +407,12 @@
}
@Provides
+ @Application
+ static AssetManager provideAssetManager(@Application Context context) {
+ return context.getAssets();
+ }
+
+ @Provides
@Singleton
static RoleManager provideRoleManager(Context context) {
return context.getSystemService(RoleManager.class);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 4e48a52..c4fca60 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -35,6 +35,7 @@
import com.android.systemui.dock.DockManagerImpl;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.media.dagger.MediaModule;
+import com.android.systemui.navigationbar.gestural.GestureModule;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.EnhancedEstimates;
@@ -94,6 +95,7 @@
* SystemUI code that variants of SystemUI _must_ include to function correctly.
*/
@Module(includes = {
+ GestureModule.class,
MediaModule.class,
PowerModule.class,
QSModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 3039d9d..bd6a5fc 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -59,7 +59,6 @@
import com.android.internal.policy.GestureNavigationSettingsObserver;
import com.android.internal.util.LatencyTracker;
import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
@@ -96,6 +95,7 @@
import java.util.function.Consumer;
import javax.inject.Inject;
+import javax.inject.Provider;
/**
* Utility class to handle edge swipes for back gesture
@@ -196,6 +196,8 @@
private final Region mExcludeRegion = new Region();
private final Region mUnrestrictedExcludeRegion = new Region();
private final LatencyTracker mLatencyTracker;
+ private final Provider<BackGestureTfClassifierProvider>
+ mBackGestureTfClassifierProviderProvider;
private final FeatureFlags mFeatureFlags;
// The left side edge width where touch down is allowed
@@ -316,6 +318,7 @@
Optional<Pip> pipOptional,
FalsingManager falsingManager,
LatencyTracker latencyTracker,
+ Provider<BackGestureTfClassifierProvider> backGestureTfClassifierProviderProvider,
FeatureFlags featureFlags) {
super(broadcastDispatcher);
mContext = context;
@@ -333,6 +336,7 @@
mPipOptional = pipOptional;
mFalsingManager = falsingManager;
mLatencyTracker = latencyTracker;
+ mBackGestureTfClassifierProviderProvider = backGestureTfClassifierProviderProvider;
mFeatureFlags = featureFlags;
ComponentName recentsComponentName = ComponentName.unflattenFromString(
context.getString(com.android.internal.R.string.config_recentsComponentName));
@@ -612,10 +616,7 @@
}
if (newState) {
- String mlModelName = DeviceConfig.getString(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.BACK_GESTURE_ML_MODEL_NAME, "backgesture");
- mBackGestureTfClassifierProvider = SystemUIFactory.getInstance()
- .createBackGestureTfClassifierProvider(mContext.getAssets(), mlModelName);
+ mBackGestureTfClassifierProvider = mBackGestureTfClassifierProviderProvider.get();
mMLModelThreshold = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.BACK_GESTURE_ML_MODEL_THRESHOLD, 0.9f);
if (mBackGestureTfClassifierProvider.isActive()) {
@@ -1007,6 +1008,8 @@
private final Optional<Pip> mPipOptional;
private final FalsingManager mFalsingManager;
private final LatencyTracker mLatencyTracker;
+ private final Provider<BackGestureTfClassifierProvider>
+ mBackGestureTfClassifierProviderProvider;
private final FeatureFlags mFeatureFlags;
@Inject
@@ -1024,6 +1027,8 @@
Optional<Pip> pipOptional,
FalsingManager falsingManager,
LatencyTracker latencyTracker,
+ Provider<BackGestureTfClassifierProvider>
+ backGestureTfClassifierProviderProvider,
FeatureFlags featureFlags) {
mOverviewProxyService = overviewProxyService;
mSysUiState = sysUiState;
@@ -1039,6 +1044,7 @@
mPipOptional = pipOptional;
mFalsingManager = falsingManager;
mLatencyTracker = latencyTracker;
+ mBackGestureTfClassifierProviderProvider = backGestureTfClassifierProviderProvider;
mFeatureFlags = featureFlags;
}
@@ -1060,6 +1066,7 @@
mPipOptional,
mFalsingManager,
mLatencyTracker,
+ mBackGestureTfClassifierProviderProvider,
mFeatureFlags);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/GestureModule.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/GestureModule.java
new file mode 100644
index 0000000..f98496d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/GestureModule.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.navigationbar.gestural;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ *
+ */
+@Module
+public interface GestureModule {
+ /** */
+ @Provides
+ static BackGestureTfClassifierProvider providsBackGestureTfClassifierProvider() {
+ return new BackGestureTfClassifierProvider();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index 1004fca..ee49b29 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -57,8 +57,6 @@
private boolean mCharging;
private boolean mPluggedIn;
- private Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_battery_saver);
-
@Inject
public BatterySaverTile(
QSHost host,
@@ -145,7 +143,9 @@
protected void handleUpdateState(BooleanState state, Object arg) {
state.state = mPluggedIn ? Tile.STATE_UNAVAILABLE
: mPowerSave ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
- state.icon = mIcon;
+ state.icon = ResourceIcon.get(mPowerSave
+ ? R.drawable.qs_battery_saver_icon_on
+ : R.drawable.qs_battery_saver_icon_off);
state.label = mContext.getString(R.string.battery_detail_switch_title);
state.secondaryLabel = "";
state.contentDescription = state.label;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
index f4f0b2c..e547095 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
@@ -72,9 +72,9 @@
@Override
public @DrawableRes int getIconRes(boolean isBlocked) {
if (isBlocked) {
- return com.android.internal.R.drawable.ic_mic_blocked;
+ return R.drawable.qs_mic_access_off;
} else {
- return com.android.internal.R.drawable.ic_mic_allowed;
+ return R.drawable.qs_mic_access_on;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 7d53abf..eb2ee9d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -2693,7 +2693,8 @@
@Override
public void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
boolean afterKeyguardGone) {
- if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP
+ if (!action.willRunAnimationOnKeyguard()
+ && mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP
&& mKeyguardStateController.canDismissLockScreen()
&& !mStatusBarStateController.leaveOpenOnKeyguardHide()
&& mDozeServiceHost.isPulsing()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index 5bd20ff..a29ba91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -68,6 +68,7 @@
mBrightnessMirror.setVisibility(View.INVISIBLE);
});
mVisibilityCallback = visibilityCallback;
+ updateResources();
}
public void showMirror() {
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index 9a19d8d..36a49af 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -35,6 +35,7 @@
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
import com.android.systemui.doze.DozeHost;
+import com.android.systemui.navigationbar.gestural.GestureModule;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.EnhancedEstimates;
@@ -87,6 +88,7 @@
* overridden by the System UI implementation.
*/
@Module(includes = {
+ GestureModule.class,
PowerModule.class,
QSModule.class,
VolumeModule.class,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
index 3d9205e..95e7ad9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
@@ -24,15 +24,19 @@
import android.view.View
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.settings.SecureSettings
+import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
@@ -77,6 +81,7 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
testableLooper = TestableLooper.get(this)
+ `when`(qsHost.context).thenReturn(mContext)
`when`(qsHost.userContext).thenReturn(userContext)
`when`(userContext.userId).thenReturn(USER)
@@ -133,4 +138,26 @@
tile.handleSetListening(false)
verify(batteryController).clearLastPowerSaverStartView()
}
+
+ @Test
+ fun testIcon_whenBatterySaverDisabled_isOffState() {
+ val state = QSTile.BooleanState()
+ tile.onPowerSaveChanged(false)
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_battery_saver_icon_off))
+ }
+
+ @Test
+ fun testIcon_whenBatterySaverEnabled_isOnState() {
+ val state = QSTile.BooleanState()
+ tile.onPowerSaveChanged(true)
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_battery_saver_icon_on))
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt
new file mode 100644
index 0000000..1ab601c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles
+
+import android.os.Handler
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.UiEventLogger
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.qs.QSHost
+import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class MicrophoneToggleTileTest : SysuiTestCase() {
+ companion object {
+ /* isBlocked */
+ const val MICROPHONE_TOGGLE_ENABLED: Boolean = false
+ const val MICROPHONE_TOGGLE_DISABLED: Boolean = true
+ }
+
+ @Mock
+ private lateinit var host: QSHost
+ @Mock
+ private lateinit var metricsLogger: MetricsLogger
+ @Mock
+ private lateinit var statusBarStateController: StatusBarStateController
+ @Mock
+ private lateinit var activityStarter: ActivityStarter
+ @Mock
+ private lateinit var qsLogger: QSLogger
+ @Mock
+ private lateinit var privacyController: IndividualSensorPrivacyController
+ @Mock
+ private lateinit var keyguardStateController: KeyguardStateController
+
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var tile: MicrophoneToggleTile
+ private val uiEventLogger: UiEventLogger = UiEventLoggerFake()
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ testableLooper = TestableLooper.get(this)
+ whenever(host.context).thenReturn(mContext)
+ whenever(host.uiEventLogger).thenReturn(uiEventLogger)
+
+ tile = MicrophoneToggleTile(host,
+ testableLooper.looper,
+ Handler(testableLooper.looper),
+ metricsLogger,
+ FalsingManagerFake(),
+ statusBarStateController,
+ activityStarter,
+ qsLogger,
+ privacyController,
+ keyguardStateController)
+ }
+
+ @Test
+ fun testIcon_whenMicrophoneAccessEnabled_isOnState() {
+ val state = QSTile.BooleanState()
+
+ tile.handleUpdateState(state, MICROPHONE_TOGGLE_ENABLED)
+
+ assertThat(state.icon).isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_mic_access_on))
+ }
+
+ @Test
+ fun testIcon_whenMicrophoneAccessDisabled_isOffState() {
+ val state = QSTile.BooleanState()
+
+ tile.handleUpdateState(state, MICROPHONE_TOGGLE_DISABLED)
+
+ assertThat(state.icon).isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_mic_access_off))
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
index 7e245fc..7982bc0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
@@ -37,94 +37,94 @@
import com.android.systemui.statusbar.window.StatusBarWindowStateController
import com.android.systemui.tuner.TunerService
import com.google.common.truth.Truth.assertThat
+import java.util.Optional
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
import org.mockito.Mock
-import org.mockito.MockitoAnnotations
import org.mockito.Mockito.anyFloat
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import java.util.Optional
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
- private lateinit var mController: NotificationShadeWindowViewController
-
@Mock
- private lateinit var mView: NotificationShadeWindowView
+ private lateinit var view: NotificationShadeWindowView
@Mock
- private lateinit var mTunerService: TunerService
+ private lateinit var tunserService: TunerService
@Mock
- private lateinit var mStatusBarStateController: SysuiStatusBarStateController
+ private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
@Mock
- private lateinit var mCentralSurfaces: CentralSurfaces
+ private lateinit var centralSurfaces: CentralSurfaces
@Mock
- private lateinit var mDockManager: DockManager
+ private lateinit var dockManager: DockManager
@Mock
- private lateinit var mNotificationPanelViewController: NotificationPanelViewController
+ private lateinit var notificationPanelViewController: NotificationPanelViewController
@Mock
- private lateinit var mNotificationShadeDepthController: NotificationShadeDepthController
+ private lateinit var notificationShadeDepthController: NotificationShadeDepthController
@Mock
- private lateinit var mNotificationShadeWindowController: NotificationShadeWindowController
+ private lateinit var notificationShadeWindowController: NotificationShadeWindowController
@Mock
- private lateinit var mKeyguardUnlockAnimationController: KeyguardUnlockAnimationController
+ private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
@Mock
- private lateinit var mAmbientState: AmbientState
+ private lateinit var ambientState: AmbientState
@Mock
private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController
@Mock
- private lateinit var mStatusBarKeyguardViewManager: StatusBarKeyguardViewManager
+ private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
@Mock
- private lateinit var mStatusBarWindowStateController: StatusBarWindowStateController
+ private lateinit var statusBarWindowStateController: StatusBarWindowStateController
@Mock
- private lateinit var mLockscreenShadeTransitionController: LockscreenShadeTransitionController
+ private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
@Mock
- private lateinit var mLockIconViewController: LockIconViewController
+ private lateinit var lockIconViewController: LockIconViewController
@Mock
- private lateinit var mPhoneStatusBarViewController: PhoneStatusBarViewController
+ private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController
@Mock
- private lateinit var mLowLightClockController: LowLightClockController
+ private lateinit var lowLightClockController: LowLightClockController
- private lateinit var mInteractionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
- private lateinit var mInteractionEventHandler: InteractionEventHandler
+ private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
+ private lateinit var interactionEventHandler: InteractionEventHandler
+
+ private lateinit var underTest: NotificationShadeWindowViewController
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- whenever(mView.bottom).thenReturn(VIEW_BOTTOM)
+ whenever(view.bottom).thenReturn(VIEW_BOTTOM)
- mController = NotificationShadeWindowViewController(
- mLockscreenShadeTransitionController,
+ underTest = NotificationShadeWindowViewController(
+ lockscreenShadeTransitionController,
FalsingCollectorFake(),
- mTunerService,
- mStatusBarStateController,
- mDockManager,
- mNotificationShadeDepthController,
- mView,
- mNotificationPanelViewController,
+ tunserService,
+ sysuiStatusBarStateController,
+ dockManager,
+ notificationShadeDepthController,
+ view,
+ notificationPanelViewController,
PanelExpansionStateManager(),
stackScrollLayoutController,
- mStatusBarKeyguardViewManager,
- mStatusBarWindowStateController,
- mLockIconViewController,
- Optional.of(mLowLightClockController),
- mCentralSurfaces,
- mNotificationShadeWindowController,
- mKeyguardUnlockAnimationController,
- mAmbientState
+ statusBarKeyguardViewManager,
+ statusBarWindowStateController,
+ lockIconViewController,
+ Optional.of(lowLightClockController),
+ centralSurfaces,
+ notificationShadeWindowController,
+ keyguardUnlockAnimationController,
+ ambientState
)
- mController.setupExpandedStatusBar()
+ underTest.setupExpandedStatusBar()
- mInteractionEventHandlerCaptor =
+ interactionEventHandlerCaptor =
ArgumentCaptor.forClass(InteractionEventHandler::class.java)
- verify(mView).setInteractionEventHandler(mInteractionEventHandlerCaptor.capture())
- mInteractionEventHandler = mInteractionEventHandlerCaptor.value
+ verify(view).setInteractionEventHandler(interactionEventHandlerCaptor.capture())
+ interactionEventHandler = interactionEventHandlerCaptor.value
}
// Note: So far, these tests only cover interactions with the status bar view controller. More
@@ -132,148 +132,148 @@
@Test
fun handleDispatchTouchEvent_nullStatusBarViewController_returnsFalse() {
- mController.setStatusBarViewController(null)
+ underTest.setStatusBarViewController(null)
- val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv)
+ val returnVal = interactionEventHandler.handleDispatchTouchEvent(downEv)
assertThat(returnVal).isFalse()
}
@Test
fun handleDispatchTouchEvent_downTouchBelowView_sendsTouchToSb() {
- mController.setStatusBarViewController(mPhoneStatusBarViewController)
+ underTest.setStatusBarViewController(phoneStatusBarViewController)
val ev = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0)
- whenever(mPhoneStatusBarViewController.sendTouchToView(ev)).thenReturn(true)
+ whenever(phoneStatusBarViewController.sendTouchToView(ev)).thenReturn(true)
- val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(ev)
+ val returnVal = interactionEventHandler.handleDispatchTouchEvent(ev)
- verify(mPhoneStatusBarViewController).sendTouchToView(ev)
+ verify(phoneStatusBarViewController).sendTouchToView(ev)
assertThat(returnVal).isTrue()
}
@Test
fun handleDispatchTouchEvent_downTouchBelowViewThenAnotherTouch_sendsTouchToSb() {
- mController.setStatusBarViewController(mPhoneStatusBarViewController)
+ underTest.setStatusBarViewController(phoneStatusBarViewController)
val downEvBelow = MotionEvent.obtain(
0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0
)
- mInteractionEventHandler.handleDispatchTouchEvent(downEvBelow)
+ interactionEventHandler.handleDispatchTouchEvent(downEvBelow)
val nextEvent = MotionEvent.obtain(
0L, 0L, MotionEvent.ACTION_MOVE, 0f, VIEW_BOTTOM + 5f, 0
)
- whenever(mPhoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true)
+ whenever(phoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true)
- val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(nextEvent)
+ val returnVal = interactionEventHandler.handleDispatchTouchEvent(nextEvent)
- verify(mPhoneStatusBarViewController).sendTouchToView(nextEvent)
+ verify(phoneStatusBarViewController).sendTouchToView(nextEvent)
assertThat(returnVal).isTrue()
}
@Test
fun handleDispatchTouchEvent_downAndPanelCollapsedAndInSbBoundAndSbWindowShow_sendsTouchToSb() {
- mController.setStatusBarViewController(mPhoneStatusBarViewController)
- whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(true)
- whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true)
- whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
+ underTest.setStatusBarViewController(phoneStatusBarViewController)
+ whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
+ whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+ whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(true)
- whenever(mPhoneStatusBarViewController.sendTouchToView(downEv)).thenReturn(true)
+ whenever(phoneStatusBarViewController.sendTouchToView(downEv)).thenReturn(true)
- val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv)
+ val returnVal = interactionEventHandler.handleDispatchTouchEvent(downEv)
- verify(mPhoneStatusBarViewController).sendTouchToView(downEv)
+ verify(phoneStatusBarViewController).sendTouchToView(downEv)
assertThat(returnVal).isTrue()
}
@Test
fun handleDispatchTouchEvent_panelNotCollapsed_returnsNull() {
- mController.setStatusBarViewController(mPhoneStatusBarViewController)
- whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(true)
- whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
+ underTest.setStatusBarViewController(phoneStatusBarViewController)
+ whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
+ whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(true)
// Item we're testing
- whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(false)
+ whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(false)
- val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv)
+ val returnVal = interactionEventHandler.handleDispatchTouchEvent(downEv)
- verify(mPhoneStatusBarViewController, never()).sendTouchToView(downEv)
+ verify(phoneStatusBarViewController, never()).sendTouchToView(downEv)
assertThat(returnVal).isNull()
}
@Test
fun handleDispatchTouchEvent_touchNotInSbBounds_returnsNull() {
- mController.setStatusBarViewController(mPhoneStatusBarViewController)
- whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(true)
- whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true)
+ underTest.setStatusBarViewController(phoneStatusBarViewController)
+ whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
+ whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
// Item we're testing
- whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
+ whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(false)
- val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv)
+ val returnVal = interactionEventHandler.handleDispatchTouchEvent(downEv)
- verify(mPhoneStatusBarViewController, never()).sendTouchToView(downEv)
+ verify(phoneStatusBarViewController, never()).sendTouchToView(downEv)
assertThat(returnVal).isNull()
}
@Test
fun handleDispatchTouchEvent_sbWindowNotShowing_noSendTouchToSbAndReturnsTrue() {
- mController.setStatusBarViewController(mPhoneStatusBarViewController)
- whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true)
- whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
+ underTest.setStatusBarViewController(phoneStatusBarViewController)
+ whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+ whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(true)
// Item we're testing
- whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(false)
+ whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(false)
- val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv)
+ val returnVal = interactionEventHandler.handleDispatchTouchEvent(downEv)
- verify(mPhoneStatusBarViewController, never()).sendTouchToView(downEv)
+ verify(phoneStatusBarViewController, never()).sendTouchToView(downEv)
assertThat(returnVal).isTrue()
}
@Test
fun handleDispatchTouchEvent_downEventSentToSbThenAnotherEvent_sendsTouchToSb() {
- mController.setStatusBarViewController(mPhoneStatusBarViewController)
- whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(true)
- whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true)
- whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
+ underTest.setStatusBarViewController(phoneStatusBarViewController)
+ whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
+ whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+ whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
.thenReturn(true)
// Down event first
- mInteractionEventHandler.handleDispatchTouchEvent(downEv)
+ interactionEventHandler.handleDispatchTouchEvent(downEv)
// Then another event
val nextEvent = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
- whenever(mPhoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true)
+ whenever(phoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true)
- val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(nextEvent)
+ val returnVal = interactionEventHandler.handleDispatchTouchEvent(nextEvent)
- verify(mPhoneStatusBarViewController).sendTouchToView(nextEvent)
+ verify(phoneStatusBarViewController).sendTouchToView(nextEvent)
assertThat(returnVal).isTrue()
}
@Test
fun testLowLightClockAttachedWhenExpandedStatusBarSetup() {
- verify(mLowLightClockController).attachLowLightClockView(ArgumentMatchers.any())
+ verify(lowLightClockController).attachLowLightClockView(ArgumentMatchers.any())
}
@Test
fun testLowLightClockShownWhenDozing() {
- mController.setDozing(true)
- verify(mLowLightClockController).showLowLightClock(true)
+ underTest.setDozing(true)
+ verify(lowLightClockController).showLowLightClock(true)
}
@Test
fun testLowLightClockDozeTimeTickCalled() {
- mController.dozeTimeTick()
- verify(mLowLightClockController).dozeTimeTick()
+ underTest.dozeTimeTick()
+ verify(lowLightClockController).dozeTimeTick()
}
@Test
fun testLowLightClockHiddenWhenNotDozing() {
- mController.setDozing(true)
- verify(mLowLightClockController).showLowLightClock(true)
- mController.setDozing(false)
- verify(mLowLightClockController).showLowLightClock(false)
+ underTest.setDozing(true)
+ verify(lowLightClockController).showLowLightClock(true)
+ underTest.setDozing(false)
+ verify(lowLightClockController).showLowLightClock(false)
}
}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 1af8ad3..84707a8 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -398,18 +398,7 @@
final IBinder.DeathRecipient mDeathRecipient;
private final RemoteCallbackList<IPredictionCallback> mCallbacks =
- new RemoteCallbackList<IPredictionCallback>() {
- @Override
- public void onCallbackDied(IPredictionCallback callback) {
- if (DEBUG) {
- Slog.d(TAG, "Binder died for session Id=" + mSessionId
- + " and callback=" + callback.asBinder());
- }
- if (mCallbacks.getRegisteredCallbackCount() == 0) {
- destroy();
- }
- }
- };
+ new RemoteCallbackList<>();
AppPredictionSessionInfo(
@NonNull final AppPredictionSessionId id,
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d4155d1..867be24 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -224,6 +224,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
+import static com.android.server.wm.WindowManagerService.sEnableShellTransitions;
import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
@@ -3149,15 +3150,10 @@
mWillCloseOrEnterPip = willCloseOrEnterPip;
}
- /**
- * Returns whether this {@link ActivityRecord} is considered closing. Conditions are either
- * 1. Is this app animating and was requested to be hidden
- * 2. App is delayed closing since it might enter PIP.
- */
- boolean isClosingOrEnteringPip() {
- return (isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_APP_TRANSITION)
- && !mVisibleRequested) || mWillCloseOrEnterPip;
+ boolean willCloseOrEnterPip() {
+ return mWillCloseOrEnterPip;
}
+
/**
* @return Whether AppOps allows this package to enter picture-in-picture.
*/
@@ -5272,12 +5268,19 @@
}
final int windowsCount = mChildren.size();
+ // With Shell-Transition, the activity will running a transition when it is visible.
+ // It won't be included when fromTransition is true means the call from finishTransition.
+ final boolean runningAnimation = sEnableShellTransitions ? visible
+ : isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION);
for (int i = 0; i < windowsCount; i++) {
- mChildren.get(i).onAppVisibilityChanged(visible, isAnimating(PARENTS,
- ANIMATION_TYPE_APP_TRANSITION));
+ mChildren.get(i).onAppVisibilityChanged(visible, runningAnimation);
}
setVisible(visible);
setVisibleRequested(visible);
+ ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "commitVisibility: %s: visible=%b"
+ + " visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s",
+ this, isVisible(), mVisibleRequested, isInTransition(), runningAnimation,
+ Debug.getCallers(5));
if (!visible) {
stopFreezingScreen(true, true);
} else {
@@ -5300,9 +5303,6 @@
task.dispatchTaskInfoChangedIfNeeded(false /* force */);
task = task.getParent().asTask();
}
- ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
- "commitVisibility: %s: visible=%b mVisibleRequested=%b", this,
- isVisible(), mVisibleRequested);
final DisplayContent displayContent = getDisplayContent();
displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
if (performLayout) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 288777b..124b8a6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1362,7 +1362,7 @@
void setInsetProvider(@InternalInsetsType int type, WindowContainer win,
@Nullable TriConsumer<DisplayFrames, WindowContainer, Rect> frameProvider) {
- setInsetProvider(type, win, frameProvider, null /* imeFrameProvider */);
+ setInsetProvider(type, win, frameProvider, null /* overrideFrameProviders */);
}
/**
@@ -1371,15 +1371,18 @@
* @param type The type of inset this window provides.
* @param win The window.
* @param frameProvider Function to compute the frame, or {@code null} if the just the frame of
- * the window should be taken.
- * @param imeFrameProvider Function to compute the frame when dispatching insets to the IME, or
- * {@code null} if the normal frame should be taken.
+ * the window should be taken. Only for non-WindowState providers, nav bar
+ * and status bar.
+ * @param overrideFrameProviders Functions to compute the frame when dispatching insets to the
+ * given window types, or {@code null} if the normal frame should
+ * be taken.
*/
void setInsetProvider(@InternalInsetsType int type, WindowContainer win,
@Nullable TriConsumer<DisplayFrames, WindowContainer, Rect> frameProvider,
- @Nullable TriConsumer<DisplayFrames, WindowContainer, Rect> imeFrameProvider) {
+ @Nullable SparseArray<TriConsumer<DisplayFrames, WindowContainer, Rect>>
+ overrideFrameProviders) {
mInsetsStateController.getSourceProvider(type).setWindowContainer(win, frameProvider,
- imeFrameProvider);
+ overrideFrameProviders);
}
InsetsStateController getInsetsStateController() {
@@ -3865,7 +3868,7 @@
mAtmService.onImeWindowSetOnDisplayArea(imePid, mImeWindowsContainer);
}
mInsetsStateController.getSourceProvider(ITYPE_IME).setWindowContainer(win,
- mDisplayPolicy.getImeSourceFrameProvider(), null /* imeFrameProvider */);
+ mDisplayPolicy.getImeSourceFrameProvider(), null);
computeImeTarget(true /* updateImeTarget */);
updateImeControlTarget();
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 95f7618..98a51a9 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -46,9 +46,9 @@
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
@@ -1156,7 +1156,7 @@
break;
case TYPE_NAVIGATION_BAR:
mNavigationBar = win;
- mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, win,
+ final TriConsumer<DisplayFrames, WindowContainer, Rect> navFrameProvider =
(displayFrames, windowContainer, inOutFrame) -> {
if (!mNavButtonForcedVisible) {
final LayoutParams lp =
@@ -1166,19 +1166,22 @@
if (provider.type != ITYPE_NAVIGATION_BAR) {
continue;
}
- calculateInsetsFrame(displayFrames, win, inOutFrame,
- provider.source, provider.insetsSize,
- lp.privateFlags, lp.gravity
- );
+ InsetsFrameProvider.calculateInsetsFrame(
+ displayFrames.mUnrestricted,
+ win.getBounds(), displayFrames.mDisplayCutoutSafe,
+ inOutFrame, provider.source,
+ provider.insetsSize, lp.privateFlags);
}
}
inOutFrame.inset(win.mGivenContentInsets);
}
- },
-
- (displayFrames, windowContainer, inOutFrame) -> {
- // For IME, we don't modify the frame.
- });
+ };
+ final SparseArray<TriConsumer<DisplayFrames, WindowContainer, Rect>> imeOverride =
+ new SparseArray<>();
+ // For IME, we don't modify the frame.
+ imeOverride.put(TYPE_INPUT_METHOD, null);
+ mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, win,
+ navFrameProvider, imeOverride);
mDisplayContent.setInsetProvider(ITYPE_BOTTOM_MANDATORY_GESTURES, win,
(displayFrames, windowContainer, inOutFrame) -> {
@@ -1246,25 +1249,48 @@
final LayoutParams lp =
win.mAttrs.forRotation(displayFrames.mRotation);
final InsetsFrameProvider ifp =
- lp.providedInsets[index];
- calculateInsetsFrame(displayFrames, windowContainer,
- inOutFrame, ifp.source, ifp.insetsSize,
- lp.privateFlags, lp.gravity);
+ win.mAttrs.forRotation(displayFrames.mRotation)
+ .providedInsets[index];
+ InsetsFrameProvider.calculateInsetsFrame(
+ displayFrames.mUnrestricted,
+ windowContainer.getBounds(),
+ displayFrames.mDisplayCutoutSafe,
+ inOutFrame, ifp.source,
+ ifp.insetsSize, lp.privateFlags);
} : null;
- final TriConsumer<DisplayFrames, WindowContainer, Rect> imeFrameProvider =
- provider.imeInsetsSize != null
- ? (displayFrames, windowContainer, inOutFrame) -> {
- inOutFrame.inset(win.mGivenContentInsets);
- final LayoutParams lp =
- win.mAttrs.forRotation(displayFrames.mRotation);
- final InsetsFrameProvider ifp =
- lp.providedInsets[index];
- calculateInsetsFrame(displayFrames, windowContainer,
- inOutFrame, ifp.source, ifp.imeInsetsSize,
- lp.privateFlags, lp.gravity);
- } : null;
+ final InsetsFrameProvider.InsetsSizeOverride[] overrides =
+ provider.insetsSizeOverrides;
+ final SparseArray<TriConsumer<DisplayFrames, WindowContainer, Rect>>
+ overrideProviders;
+ if (overrides != null) {
+ overrideProviders = new SparseArray<>();
+ for (int j = overrides.length - 1; j >= 0; j--) {
+ final int overrideIndex = j;
+ final TriConsumer<DisplayFrames, WindowContainer, Rect>
+ overrideFrameProvider =
+ (displayFrames, windowContainer, inOutFrame) -> {
+ final LayoutParams lp =
+ win.mAttrs.forRotation(
+ displayFrames.mRotation);
+ final InsetsFrameProvider ifp =
+ win.mAttrs.providedInsets[index];
+ InsetsFrameProvider.calculateInsetsFrame(
+ displayFrames.mUnrestricted,
+ windowContainer.getBounds(),
+ displayFrames.mDisplayCutoutSafe,
+ inOutFrame, ifp.source,
+ ifp.insetsSizeOverrides[
+ overrideIndex].insetsSize,
+ lp.privateFlags);
+ };
+ overrideProviders.put(overrides[j].windowType,
+ overrideFrameProvider);
+ }
+ } else {
+ overrideProviders = null;
+ }
mDisplayContent.setInsetProvider(provider.type, win, frameProvider,
- imeFrameProvider);
+ overrideProviders);
mInsetsSourceWindowsExceptIme.add(win);
}
}
@@ -1272,40 +1298,6 @@
}
}
- private void calculateInsetsFrame(DisplayFrames df, WindowContainer container, Rect inOutFrame,
- int source, Insets insetsSize, @LayoutParams.PrivateFlags int privateFlags,
- int windowGravity) {
- boolean extendByCutout = false;
- if (source == InsetsFrameProvider.SOURCE_DISPLAY) {
- inOutFrame.set(df.mUnrestricted);
- } else if (source == InsetsFrameProvider.SOURCE_CONTAINER_BOUNDS) {
- inOutFrame.set(container.getBounds());
- } else {
- extendByCutout = (privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0;
- }
- if (insetsSize == null) {
- return;
- }
- // Only one side of the provider shall be applied. Check in the order of left - top -
- // right - bottom, only the first non-zero value will be applied.
- if (insetsSize.left != 0) {
- inOutFrame.right = inOutFrame.left + insetsSize.left;
- } else if (insetsSize.top != 0) {
- inOutFrame.bottom = inOutFrame.top + insetsSize.top;
- } else if (insetsSize.right != 0) {
- inOutFrame.left = inOutFrame.right - insetsSize.right;
- } else if (insetsSize.bottom != 0) {
- inOutFrame.top = inOutFrame.bottom - insetsSize.bottom;
- } else {
- inOutFrame.setEmpty();
- }
-
- if (extendByCutout) {
- WindowLayout.extendFrameByCutout(windowGravity, df.mDisplayCutoutSafe,
- df.mUnrestricted, inOutFrame, sTmpRect);
- }
- }
-
@WindowManagerPolicy.AltBarPosition
private int getAltBarPosition(WindowManager.LayoutParams params) {
switch (params.gravity) {
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 0d4cfa3..3e6e06a 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -234,7 +234,7 @@
//
private static boolean isImeLayeringTarget(@NonNull InsetsControlTarget target,
@NonNull InsetsControlTarget dcTarget) {
- return !dcTarget.getWindow().isClosing() && target == dcTarget;
+ return !isImeTargetWindowClosing(dcTarget.getWindow()) && target == dcTarget;
}
private static boolean isAboveImeLayeringTarget(@NonNull InsetsControlTarget target,
@@ -256,7 +256,14 @@
final InsetsControlTarget target = mDisplayContent.getImeTarget(IME_TARGET_CONTROL);
return target == mImeRequester
&& (mImeRequester.getWindow() == null
- || !mImeRequester.getWindow().isClosing());
+ || !isImeTargetWindowClosing(mImeRequester.getWindow()));
+ }
+
+ private static boolean isImeTargetWindowClosing(@NonNull WindowState win) {
+ return win.mAnimatingExit || win.mActivityRecord != null
+ && (win.mActivityRecord.isInTransition()
+ && !win.mActivityRecord.isVisibleRequested()
+ || win.mActivityRecord.willCloseOrEnterPip());
}
private boolean isTargetChangedWithinActivity(InsetsControlTarget target) {
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index ee1ff2c..620a56d 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -289,7 +289,7 @@
// contains all insets types.
final InsetsState originalState = mDisplayContent.getInsetsPolicy()
.enforceInsetsPolicyForTarget(type, WINDOWING_MODE_FULLSCREEN, alwaysOnTop,
- mStateController.getRawInsetsState());
+ attrs.type, mStateController.getRawInsetsState());
InsetsState state = adjustVisibilityForTransientTypes(originalState);
return adjustInsetsForRoundedCorners(token, state, state == originalState);
}
@@ -351,12 +351,13 @@
* @param type the inset type provided by the target
* @param windowingMode the windowing mode of the target
* @param isAlwaysOnTop is the target always on top
+ * @param windowType the type of the target
* @param state the input inset state containing all the sources
* @return The state stripped of the necessary information.
*/
InsetsState enforceInsetsPolicyForTarget(@InternalInsetsType int type,
@WindowConfiguration.WindowingMode int windowingMode, boolean isAlwaysOnTop,
- InsetsState state) {
+ int windowType, InsetsState state) {
boolean stateCopied = false;
if (type != ITYPE_INVALID) {
@@ -377,21 +378,20 @@
if (type == ITYPE_STATUS_BAR || type == ITYPE_CLIMATE_BAR) {
state.removeSource(ITYPE_CAPTION_BAR);
}
-
- // IME needs different frames for certain cases (e.g. navigation bar in gesture nav).
- if (type == ITYPE_IME) {
- ArrayMap<Integer, WindowContainerInsetsSourceProvider> providers = mStateController
- .getSourceProviders();
- for (int i = providers.size() - 1; i >= 0; i--) {
- WindowContainerInsetsSourceProvider otherProvider = providers.valueAt(i);
- if (otherProvider.overridesImeFrame()) {
- InsetsSource override =
- new InsetsSource(
- state.getSource(otherProvider.getSource().getType()));
- override.setFrame(otherProvider.getImeOverrideFrame());
- state.addSource(override);
- }
+ }
+ ArrayMap<Integer, WindowContainerInsetsSourceProvider> providers = mStateController
+ .getSourceProviders();
+ for (int i = providers.size() - 1; i >= 0; i--) {
+ WindowContainerInsetsSourceProvider otherProvider = providers.valueAt(i);
+ if (otherProvider.overridesFrame(windowType)) {
+ if (!stateCopied) {
+ state = new InsetsState(state);
+ stateCopied = true;
}
+ InsetsSource override =
+ new InsetsSource(state.getSource(otherProvider.getSource().getType()));
+ override.setFrame(otherProvider.getOverriddenFrame(windowType));
+ state.addSource(override);
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 610bf05..86a73c9 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -27,7 +27,6 @@
import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL;
import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL_TARGET;
import static com.android.server.wm.InsetsSourceProviderProto.FRAME;
-import static com.android.server.wm.InsetsSourceProviderProto.IME_OVERRIDDEN_FRAME;
import static com.android.server.wm.InsetsSourceProviderProto.IS_LEASH_READY_FOR_DISPATCHING;
import static com.android.server.wm.InsetsSourceProviderProto.PENDING_CONTROL_TARGET;
import static com.android.server.wm.InsetsSourceProviderProto.SEAMLESS_ROTATING;
@@ -41,6 +40,7 @@
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
+import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsFrameProvider;
import android.view.InsetsSource;
@@ -78,8 +78,8 @@
private @Nullable ControlAdapter mAdapter;
private TriConsumer<DisplayFrames, WindowContainer, Rect> mFrameProvider;
- private TriConsumer<DisplayFrames, WindowContainer, Rect> mImeFrameProvider;
- private final Rect mImeOverrideFrame = new Rect();
+ private SparseArray<TriConsumer<DisplayFrames, WindowContainer, Rect>> mOverrideFrameProviders;
+ private final SparseArray<Rect> mOverrideFrames = new SparseArray<Rect>();
private boolean mIsLeashReadyForDispatching;
private final Rect mSourceFrame = new Rect();
private final Rect mLastSourceFrame = new Rect();
@@ -146,12 +146,15 @@
* @param windowContainer The window container that links to this source.
* @param frameProvider Based on display frame state and the window, calculates the resulting
* frame that should be reported to clients.
- * @param imeFrameProvider Based on display frame state and the window, calculates the resulting
- * frame that should be reported to IME.
+ * This will only be used when the window container providing the insets is
+ * not a WindowState.
+ * @param overrideFrameProviders Based on display frame state and the window, calculates the
+ * resulting frame that should be reported to given window type.
*/
void setWindowContainer(@Nullable WindowContainer windowContainer,
@Nullable TriConsumer<DisplayFrames, WindowContainer, Rect> frameProvider,
- @Nullable TriConsumer<DisplayFrames, WindowContainer, Rect> imeFrameProvider) {
+ @Nullable SparseArray<TriConsumer<DisplayFrames, WindowContainer, Rect>>
+ overrideFrameProviders) {
if (mWindowContainer != null) {
if (mControllable) {
mWindowContainer.setControllableInsetProvider(null);
@@ -167,8 +170,9 @@
ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "InsetsSource setWin %s for type %s",
windowContainer, InsetsState.typeToString(mSource.getType()));
mWindowContainer = windowContainer;
+ // TODO: remove the frame provider for non-WindowState container.
mFrameProvider = frameProvider;
- mImeFrameProvider = imeFrameProvider;
+ mOverrideFrameProviders = overrideFrameProviders;
if (windowContainer == null) {
setServerVisible(false);
mSource.setVisibleFrame(null);
@@ -228,10 +232,25 @@
}
updateSourceFrameForServerVisibility();
- if (mImeFrameProvider != null) {
- mImeOverrideFrame.set(frame);
- mImeFrameProvider.accept(mWindowContainer.getDisplayContent().mDisplayFrames,
- mWindowContainer, mImeOverrideFrame);
+ if (mOverrideFrameProviders != null) {
+ for (int i = mOverrideFrameProviders.size() - 1; i >= 0; i--) {
+ final int windowType = mOverrideFrameProviders.keyAt(i);
+ final Rect overrideFrame;
+ if (mOverrideFrames.contains(windowType)) {
+ overrideFrame = mOverrideFrames.get(windowType);
+ overrideFrame.set(frame);
+ } else {
+ overrideFrame = new Rect(frame);
+ }
+ final TriConsumer<DisplayFrames, WindowContainer, Rect> provider =
+ mOverrideFrameProviders.get(windowType);
+ if (provider != null) {
+ mOverrideFrameProviders.get(windowType).accept(
+ mWindowContainer.getDisplayContent().mDisplayFrames, mWindowContainer,
+ overrideFrame);
+ }
+ mOverrideFrames.put(windowType, overrideFrame);
+ }
}
if (win.mGivenVisibleInsets.left != 0 || win.mGivenVisibleInsets.top != 0
@@ -552,32 +571,30 @@
return mClientVisible;
}
- /**
- * @return Whether this provider uses a different frame to dispatch to the IME.
- */
- boolean overridesImeFrame() {
- return mImeFrameProvider != null;
+ boolean overridesFrame(int windowType) {
+ return mOverrideFrames.contains(windowType);
}
- /**
- * @return Rect to dispatch to the IME as frame. Only valid if {@link #overridesImeFrame()}
- * returns {@code true}.
- */
- Rect getImeOverrideFrame() {
- return mImeOverrideFrame;
+ Rect getOverriddenFrame(int windowType) {
+ return mOverrideFrames.get(windowType);
}
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + getClass().getSimpleName());
prefix = prefix + " ";
pw.print(prefix + "mSource="); mSource.dump("", pw);
+ pw.print(prefix + "mSourceFrame=");
+ pw.println(mSourceFrame);
+ if (mOverrideFrames.size() > 0) {
+ pw.print(prefix + "mOverrideFrames=");
+ pw.println(mOverrideFrames);
+ }
if (mControl != null) {
pw.print(prefix + "mControl=");
mControl.dump("", pw);
}
pw.print(prefix);
pw.print("mIsLeashReadyForDispatching="); pw.print(mIsLeashReadyForDispatching);
- pw.print(" mImeOverrideFrame="); pw.print(mImeOverrideFrame.toShortString());
pw.println();
if (mWindowContainer != null) {
pw.print(prefix + "mWindowContainer=");
@@ -621,7 +638,6 @@
if (mAdapter != null && mAdapter.mCapturedLeash != null) {
mAdapter.mCapturedLeash.dumpDebug(proto, CAPTURED_LEASH);
}
- mImeOverrideFrame.dumpDebug(proto, IME_OVERRIDDEN_FRAME);
proto.write(IS_LEASH_READY_FOR_DISPATCHING, mIsLeashReadyForDispatching);
proto.write(CLIENT_VISIBLE, mClientVisible);
proto.write(SERVER_VISIBLE, mServerVisible);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 46091d8..af8c4c8 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1703,7 +1703,7 @@
mFrozenInsetsState != null ? mFrozenInsetsState : getMergedInsetsState();
final InsetsState insetsStateForWindow = insetsPolicy
.enforceInsetsPolicyForTarget(insetTypeProvidedByWindow,
- getWindowingMode(), isAlwaysOnTop(), rawInsetsState);
+ getWindowingMode(), isAlwaysOnTop(), mAttrs.type, rawInsetsState);
return insetsPolicy.adjustInsetsForWindow(this, insetsStateForWindow,
includeTransient);
}
@@ -3461,10 +3461,6 @@
return mClient.asBinder().isBinderAlive();
}
- boolean isClosing() {
- return mAnimatingExit || (mActivityRecord != null && mActivityRecord.isClosingOrEnteringPip());
- }
-
void sendAppVisibilityToClients() {
super.sendAppVisibilityToClients();
diff --git a/services/smartspace/java/com/android/server/smartspace/SmartspacePerUserService.java b/services/smartspace/java/com/android/server/smartspace/SmartspacePerUserService.java
index dcffc9e..f041fbd 100644
--- a/services/smartspace/java/com/android/server/smartspace/SmartspacePerUserService.java
+++ b/services/smartspace/java/com/android/server/smartspace/SmartspacePerUserService.java
@@ -334,18 +334,7 @@
@NonNull
private final SmartspaceConfig mSmartspaceConfig;
private final RemoteCallbackList<ISmartspaceCallback> mCallbacks =
- new RemoteCallbackList<ISmartspaceCallback>() {
- @Override
- public void onCallbackDied(ISmartspaceCallback callback) {
- if (DEBUG) {
- Slog.d(TAG, "Binder died for session Id=" + mSessionId
- + " and callback=" + callback.asBinder());
- }
- if (mCallbacks.getRegisteredCallbackCount() == 0) {
- destroy();
- }
- }
- };
+ new RemoteCallbackList<>();
SmartspaceSessionInfo(
@NonNull final SmartspaceSessionId id,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 40e266c..11a7c7d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -2118,7 +2118,6 @@
final WindowState appWin2 = createWindow(null, TYPE_BASE_APPLICATION, act2, "appWin2");
appWin2.setHasSurface(true);
assertTrue(appWin2.canBeImeTarget());
- doReturn(true).when(appWin1).isClosing();
doReturn(true).when(appWin1).inTransitionSelfOrParent();
// Test step 3: Verify appWin2 will be the next IME target and the IME snapshot surface will
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index ffa21fa..6c161cf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -27,6 +27,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -44,12 +45,15 @@
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.util.SparseArray;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.InsetsVisibilities;
import androidx.test.filters.SmallTest;
+import com.android.internal.util.function.TriConsumer;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -269,15 +273,18 @@
@Test
public void testImeForDispatch() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
- final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
+ final WindowState ime = createWindow(null, TYPE_INPUT_METHOD, "ime");
// IME cannot be the IME target.
ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
WindowContainerInsetsSourceProvider statusBarProvider =
getController().getSourceProvider(ITYPE_STATUS_BAR);
- statusBarProvider.setWindowContainer(statusBar, null, ((displayFrames, windowState, rect) ->
+ final SparseArray<TriConsumer<DisplayFrames, WindowContainer, Rect>> imeOverrideProviders =
+ new SparseArray<>();
+ imeOverrideProviders.put(TYPE_INPUT_METHOD, ((displayFrames, windowState, rect) ->
rect.set(0, 1, 2, 3)));
+ statusBarProvider.setWindowContainer(statusBar, null, imeOverrideProviders);
getController().getSourceProvider(ITYPE_IME).setWindowContainer(ime, null, null);
statusBar.setControllableInsetProvider(statusBarProvider);
statusBar.updateSourceFrame(statusBar.getFrame());