Merge "Cleans up any stray instances of KeyguardUpdateMonitor that might still have listeners attached to system services." into tm-qpr-dev
diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
index c59d757..257ad71 100644
--- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
@@ -315,17 +315,17 @@
int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
/**
- * Whether the FingerprintAcquired message is a signal to turn off HBM
+ * Whether the FingerprintAcquired message is a signal to disable the UDFPS display mode.
+ * We want to disable the UDFPS mode as soon as possible to conserve power and provide better
+ * UX. For example, prolonged high-brightness illumination of optical sensors can be unpleasant
+ * to the user, can cause long term display burn-in, and can drain the battery faster.
*/
- static boolean shouldTurnOffHbm(@FingerprintAcquired int acquiredInfo) {
+ static boolean shouldDisableUdfpsDisplayMode(@FingerprintAcquired int acquiredInfo) {
switch (acquiredInfo) {
case FINGERPRINT_ACQUIRED_START:
- // Authentication just began
+ // Keep the UDFPS mode because the authentication just began.
return false;
case FINGERPRINT_ACQUIRED_GOOD:
- // Good image captured. Turn off HBM. Success/Reject comes after, which is when
- // hideUdfpsOverlay will be called.
- return true;
case FINGERPRINT_ACQUIRED_PARTIAL:
case FINGERPRINT_ACQUIRED_INSUFFICIENT:
case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
@@ -334,11 +334,12 @@
case FINGERPRINT_ACQUIRED_IMMOBILE:
case FINGERPRINT_ACQUIRED_TOO_BRIGHT:
case FINGERPRINT_ACQUIRED_VENDOR:
- // Bad image captured. Turn off HBM. Matcher will not run, so there's no need to
- // keep HBM on.
+ // Disable the UDFPS mode because the image capture has finished. The overlay
+ // can be hidden later, once the authentication result arrives.
return true;
case FINGERPRINT_ACQUIRED_UNKNOWN:
default:
+ // Keep the UDFPS mode in case of an unknown message.
return false;
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index b0fce8f..d9df144 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -17,11 +17,19 @@
package com.android.internal.os;
import android.annotation.NonNull;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.BatteryStats;
+import android.os.BatteryStats.BitDescription;
+import android.os.BatteryStats.HistoryItem;
+import android.os.BatteryStats.HistoryTag;
+import android.os.Build;
import android.os.Parcel;
+import android.os.Process;
import android.os.StatFs;
import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.Trace;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Slog;
@@ -105,6 +113,49 @@
private int mParcelIndex = 0;
/**
+ * A delegate for android.os.Trace to allow testing static calls. Due to
+ * limitations in Android Tracing (b/153319140), the delegate also records
+ * counter values in system properties which allows reading the value at the
+ * start of a tracing session. This overhead is limited to userdebug builds.
+ * On user builds, tracing still occurs but the counter value will be missing
+ * until the first change occurs.
+ */
+ @VisibleForTesting
+ public static class TraceDelegate {
+ // Note: certain tests currently run as platform_app which is not allowed
+ // to set debug system properties. To ensure that system properties are set
+ // only when allowed, we check the current UID.
+ private final boolean mShouldSetProperty =
+ Build.IS_USERDEBUG && (Process.myUid() == Process.SYSTEM_UID);
+
+ /**
+ * Returns true if trace counters should be recorded.
+ */
+ public boolean tracingEnabled() {
+ return Trace.isTagEnabled(Trace.TRACE_TAG_POWER) || mShouldSetProperty;
+ }
+
+ /**
+ * Records the counter value with the given name.
+ */
+ public void traceCounter(@NonNull String name, int value) {
+ Trace.traceCounter(Trace.TRACE_TAG_POWER, name, value);
+ if (mShouldSetProperty) {
+ SystemProperties.set("debug.tracing." + name, Integer.toString(value));
+ }
+ }
+
+ /**
+ * Records an instant event (one with no duration).
+ */
+ public void traceInstantEvent(@NonNull String track, @NonNull String name) {
+ Trace.instantForTrack(Trace.TRACE_TAG_POWER, track, name);
+ }
+ }
+
+ private TraceDelegate mTracer = new TraceDelegate();
+
+ /**
* Constructor
* @param stats BatteryStatsImpl object.
* @param systemDir typically /data/system
@@ -497,4 +548,47 @@
}
return ret;
}
+
+ /**
+ * Writes event details into Atrace.
+ */
+ public void recordTraceEvents(int code, HistoryTag tag) {
+ if (code == HistoryItem.EVENT_NONE) return;
+ if (!mTracer.tracingEnabled()) return;
+
+ final int idx = code & HistoryItem.EVENT_TYPE_MASK;
+ final String prefix = (code & HistoryItem.EVENT_FLAG_START) != 0 ? "+" :
+ (code & HistoryItem.EVENT_FLAG_FINISH) != 0 ? "-" : "";
+
+ final String[] names = BatteryStats.HISTORY_EVENT_NAMES;
+ if (idx < 0 || idx >= BatteryStats.HISTORY_EVENT_NAMES.length) return;
+
+ final String track = "battery_stats." + names[idx];
+ final String name = prefix + names[idx] + "=" + tag.uid + ":\"" + tag.string + "\"";
+ mTracer.traceInstantEvent(track, name);
+ }
+
+ /**
+ * Writes changes to a HistoryItem state bitmap to Atrace.
+ */
+ public void recordTraceCounters(int oldval, int newval, BitDescription[] descriptions) {
+ if (!mTracer.tracingEnabled()) return;
+
+ int diff = oldval ^ newval;
+ if (diff == 0) return;
+
+ for (int i = 0; i < descriptions.length; i++) {
+ BitDescription bd = descriptions[i];
+ if ((diff & bd.mask) == 0) continue;
+
+ int value;
+ if (bd.shift < 0) {
+ value = (newval & bd.mask) != 0 ? 1 : 0;
+ } else {
+ value = (newval & bd.mask) >> bd.shift;
+ }
+
+ mTracer.traceCounter("battery_stats." + bd.name, value);
+ }
+ }
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 98d4c59..ec2bc7c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4432,6 +4432,12 @@
+ Integer.toHexString(diffStates2) + " lastDiff2="
+ Integer.toHexString(lastDiffStates2));
}
+
+ mBatteryStatsHistory.recordTraceEvents(cur.eventCode, cur.eventTag);
+ mBatteryStatsHistory.recordTraceCounters(mHistoryLastWritten.states,
+ cur.states & mActiveHistoryStates, BatteryStats.HISTORY_STATE_DESCRIPTIONS);
+ mBatteryStatsHistory.recordTraceCounters(mHistoryLastWritten.states2,
+ cur.states2 & mActiveHistoryStates2, BatteryStats.HISTORY_STATE2_DESCRIPTIONS);
if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
&& timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0
&& (diffStates2&lastDiffStates2) == 0
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c3b6df1..b94bd83 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4877,9 +4877,6 @@
-->
</array>
- <!-- How long it takes for the HW to start illuminating after the illumination is requested. -->
- <integer name="config_udfps_illumination_transition_ms">50</integer>
-
<!-- Indicates whether device has a power button fingerprint sensor. -->
<bool name="config_is_powerbutton_fps" translatable="false" >false</bool>
@@ -5218,7 +5215,7 @@
<!-- Vertical position of a center of the letterboxed app window.
0 corresponds to the upper side of the screen and 1 to the lower side. If given value < 0
or > 1, it is ignored and central position is used (0.5). -->
- <item name="config_letterboxVerticalPositionMultiplier" format="float" type="dimen">0.5</item>
+ <item name="config_letterboxVerticalPositionMultiplier" format="float" type="dimen">0.0</item>
<!-- Whether horizontal reachability repositioning is allowed for letterboxed fullscreen apps.
-->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6c6a0a3..546bb21 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2706,7 +2706,6 @@
<java-symbol type="bool" name="allow_test_udfps" />
<java-symbol type="array" name="config_udfps_sensor_props" />
<java-symbol type="array" name="config_sfps_sensor_props" />
- <java-symbol type="integer" name="config_udfps_illumination_transition_ms" />
<java-symbol type="bool" name="config_is_powerbutton_fps" />
<java-symbol type="array" name="config_udfps_enroll_stage_thresholds" />
<java-symbol type="array" name="config_sfps_enroll_stage_thresholds" />
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index c39602032..7c3c14e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -55,6 +55,8 @@
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
import com.android.wm.shell.compatui.CompatUIController;
+import com.android.wm.shell.desktopmode.DesktopMode;
+import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.displayareahelper.DisplayAreaHelperController;
import com.android.wm.shell.draganddrop.DragAndDropController;
@@ -477,11 +479,12 @@
ShellInit shellInit,
ShellCommandHandler shellCommandHandler,
TaskStackListenerImpl taskStackListener,
+ Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
@ShellMainThread ShellExecutor mainExecutor
) {
return Optional.ofNullable(
RecentTasksController.create(context, shellInit, shellCommandHandler,
- taskStackListener, mainExecutor));
+ taskStackListener, desktopModeTaskRepository, mainExecutor));
}
//
@@ -666,6 +669,24 @@
}
//
+ // Desktop mode (optional feature)
+ //
+
+ @BindsOptionalOf
+ @DynamicOverride
+ abstract DesktopModeTaskRepository optionalDesktopModeTaskRepository();
+
+ @WMSingleton
+ @Provides
+ static Optional<DesktopModeTaskRepository> providesDesktopModeTaskRepository(
+ @DynamicOverride Optional<DesktopModeTaskRepository> desktopModeTaskRepository) {
+ if (DesktopMode.IS_SUPPORTED) {
+ return desktopModeTaskRepository;
+ }
+ return Optional.empty();
+ }
+
+ //
// Misc
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 247ba60..27d3e35 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -51,6 +51,7 @@
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.desktopmode.DesktopModeController;
+import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformComponents;
import com.android.wm.shell.freeform.FreeformTaskListener;
@@ -220,14 +221,14 @@
Context context,
ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
- Optional<RecentTasksController> recentTasksController,
+ Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
WindowDecorViewModel<?> windowDecorViewModel) {
// TODO(b/238217847): Temporarily add this check here until we can remove the dynamic
// override for this controller from the base module
ShellInit init = FreeformComponents.isFreeformEnabled(context)
? shellInit
: null;
- return new FreeformTaskListener<>(init, shellTaskOrganizer, recentTasksController,
+ return new FreeformTaskListener<>(init, shellTaskOrganizer, desktopModeTaskRepository,
windowDecorViewModel);
}
@@ -610,6 +611,13 @@
}
}
+ @WMSingleton
+ @Provides
+ @DynamicOverride
+ static DesktopModeTaskRepository provideDesktopModeTaskRepository() {
+ return new DesktopModeTaskRepository();
+ }
+
//
// Misc
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
new file mode 100644
index 0000000..988601c
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
@@ -0,0 +1,89 @@
+/*
+ * 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.wm.shell.desktopmode
+
+import android.util.ArraySet
+
+/**
+ * Keeps track of task data related to desktop mode.
+ */
+class DesktopModeTaskRepository {
+
+ /**
+ * Set of task ids that are marked as active in desktop mode.
+ * Active tasks in desktop mode are freeform tasks that are visible or have been visible after
+ * desktop mode was activated.
+ * Task gets removed from this list when it vanishes. Or when desktop mode is turned off.
+ */
+ private val activeTasks = ArraySet<Int>()
+ private val listeners = ArraySet<Listener>()
+
+ /**
+ * Add a [Listener] to be notified of updates to the repository.
+ */
+ fun addListener(listener: Listener) {
+ listeners.add(listener)
+ }
+
+ /**
+ * Remove a previously registered [Listener]
+ */
+ fun removeListener(listener: Listener) {
+ listeners.remove(listener)
+ }
+
+ /**
+ * Mark a task with given [taskId] as active.
+ */
+ fun addActiveTask(taskId: Int) {
+ val added = activeTasks.add(taskId)
+ if (added) {
+ listeners.onEach { it.onActiveTasksChanged() }
+ }
+ }
+
+ /**
+ * Remove task with given [taskId] from active tasks.
+ */
+ fun removeActiveTask(taskId: Int) {
+ val removed = activeTasks.remove(taskId)
+ if (removed) {
+ listeners.onEach { it.onActiveTasksChanged() }
+ }
+ }
+
+ /**
+ * Check if a task with the given [taskId] was marked as an active task
+ */
+ fun isActiveTask(taskId: Int): Boolean {
+ return activeTasks.contains(taskId)
+ }
+
+ /**
+ * Get a set of the active tasks
+ */
+ fun getActiveTasks(): ArraySet<Int> {
+ return ArraySet(activeTasks)
+ }
+
+ /**
+ * Defines interface for classes that can listen to changes in repository state.
+ */
+ interface Listener {
+ fun onActiveTasksChanged()
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 435d8ea..62bf517 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -17,6 +17,8 @@
package com.android.wm.shell.draganddrop;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED;
+import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -263,6 +265,9 @@
mStarter.startShortcut(packageName, id, position, opts, user);
} else {
final PendingIntent launchIntent = intent.getParcelableExtra(EXTRA_PENDING_INTENT);
+ // Put BAL flags to avoid activity start aborted.
+ opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, true);
+ opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, true);
mStarter.startIntent(launchIntent, null /* fillIntent */, position, opts);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index 1baac71..ac95d4b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -29,8 +29,8 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.desktopmode.DesktopMode;
+import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
-import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
@@ -49,7 +49,7 @@
private static final String TAG = "FreeformTaskListener";
private final ShellTaskOrganizer mShellTaskOrganizer;
- private final Optional<RecentTasksController> mRecentTasksOptional;
+ private final Optional<DesktopModeTaskRepository> mDesktopModeTaskRepository;
private final WindowDecorViewModel<T> mWindowDecorationViewModel;
private final SparseArray<State<T>> mTasks = new SparseArray<>();
@@ -64,11 +64,11 @@
public FreeformTaskListener(
ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
- Optional<RecentTasksController> recentTasksController,
+ Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
WindowDecorViewModel<T> windowDecorationViewModel) {
mShellTaskOrganizer = shellTaskOrganizer;
mWindowDecorationViewModel = windowDecorationViewModel;
- mRecentTasksOptional = recentTasksController;
+ mDesktopModeTaskRepository = desktopModeTaskRepository;
if (shellInit != null) {
shellInit.addInitCallback(this::onInit, this);
}
@@ -93,7 +93,7 @@
if (DesktopMode.IS_SUPPORTED && taskInfo.isVisible) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
"Adding active freeform task: #%d", taskInfo.taskId);
- mRecentTasksOptional.ifPresent(rt -> rt.addActiveFreeformTask(taskInfo.taskId));
+ mDesktopModeTaskRepository.ifPresent(it -> it.addActiveTask(taskInfo.taskId));
}
}
@@ -126,7 +126,7 @@
if (DesktopMode.IS_SUPPORTED) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
"Removing active freeform task: #%d", taskInfo.taskId);
- mRecentTasksOptional.ifPresent(rt -> rt.removeActiveFreeformTask(taskInfo.taskId));
+ mDesktopModeTaskRepository.ifPresent(it -> it.removeActiveTask(taskInfo.taskId));
}
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
@@ -154,7 +154,7 @@
if (taskInfo.isVisible) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
"Adding active freeform task: #%d", taskInfo.taskId);
- mRecentTasksOptional.ifPresent(rt -> rt.addActiveFreeformTask(taskInfo.taskId));
+ mDesktopModeTaskRepository.ifPresent(it -> it.addActiveTask(taskInfo.taskId));
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
index e9f9bb5..7d1259a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
@@ -16,8 +16,6 @@
package com.android.wm.shell.fullscreen;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
@@ -107,13 +105,14 @@
if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
updateRecentsForVisibleFullscreenTask(taskInfo);
- if (shouldShowWindowDecor(taskInfo) && mWindowDecorViewModelOptional.isPresent()) {
+ if (mWindowDecorViewModelOptional.isPresent()) {
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
state.mWindowDecoration =
mWindowDecorViewModelOptional.get().createWindowDecoration(taskInfo,
leash, t, t);
t.apply();
- } else {
+ }
+ if (state.mWindowDecoration == null) {
mSyncQueue.runInSync(t -> {
// Reset several properties back to fullscreen (PiP, for example, leaves all these
// properties in a bad state).
@@ -178,13 +177,12 @@
public void createWindowDecoration(TransitionInfo.Change change,
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) {
final State<T> state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash());
- if (!mWindowDecorViewModelOptional.isPresent()
- || !shouldShowWindowDecor(state.mTaskInfo)) {
- return;
- }
-
- state.mWindowDecoration = mWindowDecorViewModelOptional.get().createWindowDecoration(
+ if (!mWindowDecorViewModelOptional.isPresent()) return;
+ T newWindowDecor = mWindowDecorViewModelOptional.get().createWindowDecoration(
state.mTaskInfo, state.mLeash, startT, finishT);
+ if (newWindowDecor != null) {
+ state.mWindowDecoration = newWindowDecor;
+ }
}
/**
@@ -202,8 +200,7 @@
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT,
@Nullable AutoCloseable windowDecor) {
- if (!mWindowDecorViewModelOptional.isPresent()
- || !shouldShowWindowDecor(change.getTaskInfo())) {
+ if (!mWindowDecorViewModelOptional.isPresent()) {
return false;
}
final State<T> state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash());
@@ -214,8 +211,11 @@
state.mTaskInfo, startT, finishT, state.mWindowDecoration);
return true;
} else {
- state.mWindowDecoration = mWindowDecorViewModelOptional.get().createWindowDecoration(
+ T newWindowDecor = mWindowDecorViewModelOptional.get().createWindowDecoration(
state.mTaskInfo, state.mLeash, startT, finishT);
+ if (newWindowDecor != null) {
+ state.mWindowDecoration = newWindowDecor;
+ }
return false;
}
}
@@ -256,7 +256,7 @@
windowDecor =
mWindowDecorOfVanishedTasks.removeReturnOld(taskInfo.taskId);
}
- if (mWindowDecorViewModelOptional.isPresent()) {
+ if (mWindowDecorViewModelOptional.isPresent() && windowDecor != null) {
mWindowDecorViewModelOptional.get().setupWindowDecorationForTransition(
taskInfo, startT, finishT, windowDecor);
}
@@ -336,10 +336,5 @@
return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_FULLSCREEN);
}
- private static boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
- return taskInfo.getConfiguration().windowConfiguration.getDisplayWindowingMode()
- == WINDOWING_MODE_FREEFORM;
- }
-
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 27bc1a1..ff4b2ed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -44,6 +44,7 @@
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.desktopmode.DesktopMode;
+import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellInit;
@@ -53,19 +54,20 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
/**
* Manages the recent task list from the system, caching it as necessary.
*/
public class RecentTasksController implements TaskStackListenerCallback,
- RemoteCallable<RecentTasksController> {
+ RemoteCallable<RecentTasksController>, DesktopModeTaskRepository.Listener {
private static final String TAG = RecentTasksController.class.getSimpleName();
private final Context mContext;
private final ShellCommandHandler mShellCommandHandler;
+ private final Optional<DesktopModeTaskRepository> mDesktopModeTaskRepository;
private final ShellExecutor mMainExecutor;
private final TaskStackListenerImpl mTaskStackListener;
private final RecentTasks mImpl = new RecentTasksImpl();
@@ -84,15 +86,6 @@
private final Map<Integer, SplitBounds> mTaskSplitBoundsMap = new HashMap<>();
/**
- * Set of taskId's that have been launched in freeform mode.
- * This includes tasks that are currently running, visible and in freeform mode. And also
- * includes tasks that are running in the background, are no longer visible, but at some point
- * were visible to the user.
- * This is used to decide which freeform apps belong to the user's desktop.
- */
- private final HashSet<Integer> mActiveFreeformTasks = new HashSet<>();
-
- /**
* Creates {@link RecentTasksController}, returns {@code null} if the feature is not
* supported.
*/
@@ -102,24 +95,27 @@
ShellInit shellInit,
ShellCommandHandler shellCommandHandler,
TaskStackListenerImpl taskStackListener,
+ Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
@ShellMainThread ShellExecutor mainExecutor
) {
if (!context.getResources().getBoolean(com.android.internal.R.bool.config_hasRecents)) {
return null;
}
return new RecentTasksController(context, shellInit, shellCommandHandler, taskStackListener,
- mainExecutor);
+ desktopModeTaskRepository, mainExecutor);
}
RecentTasksController(Context context,
ShellInit shellInit,
ShellCommandHandler shellCommandHandler,
TaskStackListenerImpl taskStackListener,
+ Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
ShellExecutor mainExecutor) {
mContext = context;
mShellCommandHandler = shellCommandHandler;
mIsDesktopMode = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
mTaskStackListener = taskStackListener;
+ mDesktopModeTaskRepository = desktopModeTaskRepository;
mMainExecutor = mainExecutor;
shellInit.addInitCallback(this::onInit, this);
}
@@ -131,6 +127,7 @@
private void onInit() {
mShellCommandHandler.addDumpCallback(this::dump, this);
mTaskStackListener.addListener(this);
+ mDesktopModeTaskRepository.ifPresent(it -> it.addListener(this));
}
/**
@@ -217,19 +214,8 @@
notifyRecentTasksChanged();
}
- /**
- * Mark a task with given {@code taskId} as active in freeform
- */
- public void addActiveFreeformTask(int taskId) {
- mActiveFreeformTasks.add(taskId);
- notifyRecentTasksChanged();
- }
-
- /**
- * Remove task with given {@code taskId} from active freeform tasks
- */
- public void removeActiveFreeformTask(int taskId) {
- mActiveFreeformTasks.remove(taskId);
+ @Override
+ public void onActiveTasksChanged() {
notifyRecentTasksChanged();
}
@@ -312,7 +298,8 @@
continue;
}
- if (desktopModeActive && mActiveFreeformTasks.contains(taskInfo.taskId)) {
+ if (desktopModeActive && mDesktopModeTaskRepository.isPresent()
+ && mDesktopModeTaskRepository.get().isActiveTask(taskInfo.taskId)) {
// Freeform tasks will be added as a separate entry
freeformTasks.add(taskInfo);
continue;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 025e559..3758471 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -154,7 +154,8 @@
private StageCoordinator mStageCoordinator;
// Only used for the legacy recents animation from splitscreen to allow the tasks to be animated
// outside the bounds of the roots by being reparented into a higher level fullscreen container
- private SurfaceControl mSplitTasksContainerLayer;
+ private SurfaceControl mGoingToRecentsTasksLayer;
+ private SurfaceControl mStartingSplitTasksLayer;
public SplitScreenController(Context context,
ShellInit shellInit,
@@ -509,19 +510,53 @@
}
RemoteAnimationTarget[] onGoingToRecentsLegacy(RemoteAnimationTarget[] apps) {
+ if (ENABLE_SHELL_TRANSITIONS) return null;
+
if (isSplitScreenVisible()) {
// Evict child tasks except the top visible one under split root to ensure it could be
// launched as full screen when switching to it on recents.
final WindowContainerTransaction wct = new WindowContainerTransaction();
mStageCoordinator.prepareEvictInvisibleChildTasks(wct);
mSyncQueue.queue(wct);
+ } else {
+ return null;
}
- return reparentSplitTasksForAnimation(apps, false /* enterSplitScreen */);
+
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ if (mGoingToRecentsTasksLayer != null) {
+ t.remove(mGoingToRecentsTasksLayer);
+ }
+ mGoingToRecentsTasksLayer = reparentSplitTasksForAnimation(apps, t,
+ "SplitScreenController#onGoingToRecentsLegacy" /* callsite */);
+ t.apply();
+ mTransactionPool.release(t);
+
+ return new RemoteAnimationTarget[]{mStageCoordinator.getDividerBarLegacyTarget()};
}
RemoteAnimationTarget[] onStartingSplitLegacy(RemoteAnimationTarget[] apps) {
+ if (ENABLE_SHELL_TRANSITIONS) return null;
+
+ int openingApps = 0;
+ for (int i = 0; i < apps.length; ++i) {
+ if (apps[i].mode == MODE_OPENING) openingApps++;
+ }
+ if (openingApps < 2) {
+ // Not having enough apps to enter split screen
+ return null;
+ }
+
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ if (mStartingSplitTasksLayer != null) {
+ t.remove(mStartingSplitTasksLayer);
+ }
+ mStartingSplitTasksLayer = reparentSplitTasksForAnimation(apps, t,
+ "SplitScreenController#onStartingSplitLegacy" /* callsite */);
+ t.apply();
+ mTransactionPool.release(t);
+
try {
- return reparentSplitTasksForAnimation(apps, true /* enterSplitScreen */);
+ return new RemoteAnimationTarget[]{mStageCoordinator.getDividerBarLegacyTarget()};
} finally {
for (RemoteAnimationTarget appTarget : apps) {
if (appTarget.leash != null) {
@@ -531,45 +566,23 @@
}
}
- private RemoteAnimationTarget[] reparentSplitTasksForAnimation(RemoteAnimationTarget[] apps,
- boolean enterSplitScreen) {
- if (ENABLE_SHELL_TRANSITIONS) return null;
-
- if (enterSplitScreen) {
- int openingApps = 0;
- for (int i = 0; i < apps.length; ++i) {
- if (apps[i].mode == MODE_OPENING) openingApps++;
- }
- if (openingApps < 2) {
- // Not having enough apps to enter split screen
- return null;
- }
- } else if (!isSplitScreenVisible()) {
- return null;
- }
-
- final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
- if (mSplitTasksContainerLayer != null) {
- // Remove the previous layer before recreating
- transaction.remove(mSplitTasksContainerLayer);
- }
+ private SurfaceControl reparentSplitTasksForAnimation(RemoteAnimationTarget[] apps,
+ SurfaceControl.Transaction t, String callsite) {
final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
.setContainerLayer()
.setName("RecentsAnimationSplitTasks")
.setHidden(false)
- .setCallsite("SplitScreenController#onGoingtoRecentsLegacy");
+ .setCallsite(callsite);
mRootTDAOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, builder);
- mSplitTasksContainerLayer = builder.build();
+ final SurfaceControl splitTasksLayer = builder.build();
for (int i = 0; i < apps.length; ++i) {
final RemoteAnimationTarget appTarget = apps[i];
- transaction.reparent(appTarget.leash, mSplitTasksContainerLayer);
- transaction.setPosition(appTarget.leash, appTarget.screenSpaceBounds.left,
+ t.reparent(appTarget.leash, splitTasksLayer);
+ t.setPosition(appTarget.leash, appTarget.screenSpaceBounds.left,
appTarget.screenSpaceBounds.top);
}
- transaction.apply();
- mTransactionPool.release(transaction);
- return new RemoteAnimationTarget[]{mStageCoordinator.getDividerBarLegacyTarget()};
+ return splitTasksLayer;
}
/**
* Sets drag info to be logged when splitscreen is entered.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index db35b48..25793ed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -18,8 +18,6 @@
import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED;
-import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
@@ -1109,9 +1107,6 @@
private void addActivityOptions(Bundle opts, StageTaskListener stage) {
opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, stage.mRootTaskInfo.token);
- // Put BAL flags to avoid activity start aborted.
- opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, true);
- opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, true);
}
void updateActivityOptions(Bundle opts, @SplitPosition int position) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 83aa539..e8a2cb160 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -36,6 +36,7 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
import com.android.wm.shell.transition.Transitions;
@@ -80,6 +81,7 @@
SurfaceControl taskSurface,
SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT) {
+ if (!shouldShowWindowDecor(taskInfo)) return null;
final CaptionWindowDecoration windowDecoration = new CaptionWindowDecoration(
mContext,
mDisplayController,
@@ -101,9 +103,12 @@
@Override
public CaptionWindowDecoration adoptWindowDecoration(AutoCloseable windowDecor) {
- return (windowDecor instanceof CaptionWindowDecoration)
- ? (CaptionWindowDecoration) windowDecor
- : null;
+ if (!(windowDecor instanceof CaptionWindowDecoration)) return null;
+ final CaptionWindowDecoration captionWindowDecor = (CaptionWindowDecoration) windowDecor;
+ if (!shouldShowWindowDecor(captionWindowDecor.mTaskInfo)) {
+ return null;
+ }
+ return captionWindowDecor;
}
@Override
@@ -231,4 +236,11 @@
}
}
}
+
+ private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
+ if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true;
+ return DesktopMode.IS_SUPPORTED
+ && mDisplayController.getDisplayContext(taskInfo.displayId)
+ .getResources().getConfiguration().smallestScreenWidthDp >= 600;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
index c234949..d9697d2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
@@ -42,6 +42,7 @@
/**
* Creates a window decoration for the given task.
+ * Can be {@code null} for Fullscreen tasks but not Freeform ones.
*
* @param taskInfo the initial task info of the task
* @param taskSurface the surface of the task
@@ -49,7 +50,7 @@
* @param finishT the finish transaction to restore states after the transition
* @return the window decoration object
*/
- T createWindowDecoration(
+ @Nullable T createWindowDecoration(
ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
SurfaceControl.Transaction startT,
@@ -57,11 +58,12 @@
/**
* Adopts the window decoration if possible.
+ * May be {@code null} if a window decor is not needed or the given one is incompatible.
*
* @param windowDecor the potential window decoration to adopt
* @return the window decoration if it can be adopted, or {@code null} otherwise.
*/
- T adoptWindowDecoration(@Nullable AutoCloseable windowDecor);
+ @Nullable T adoptWindowDecoration(@Nullable AutoCloseable windowDecor);
/**
* Notifies a task info update on the given task, with the window decoration created previously
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
new file mode 100644
index 0000000..9b28d11
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
@@ -0,0 +1,99 @@
+/*
+ * 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.wm.shell.desktopmode
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class DesktopModeTaskRepositoryTest : ShellTestCase() {
+
+ private lateinit var repo: DesktopModeTaskRepository
+
+ @Before
+ fun setUp() {
+ repo = DesktopModeTaskRepository()
+ }
+
+ @Test
+ fun addActiveTask_listenerNotifiedAndTaskIsActive() {
+ val listener = TestListener()
+ repo.addListener(listener)
+
+ repo.addActiveTask(1)
+ assertThat(listener.activeTaskChangedCalls).isEqualTo(1)
+ assertThat(repo.isActiveTask(1)).isTrue()
+ }
+
+ @Test
+ fun addActiveTask_sameTaskDoesNotNotify() {
+ val listener = TestListener()
+ repo.addListener(listener)
+
+ repo.addActiveTask(1)
+ repo.addActiveTask(1)
+ assertThat(listener.activeTaskChangedCalls).isEqualTo(1)
+ }
+
+ @Test
+ fun addActiveTask_multipleTasksAddedNotifiesForEach() {
+ val listener = TestListener()
+ repo.addListener(listener)
+
+ repo.addActiveTask(1)
+ repo.addActiveTask(2)
+ assertThat(listener.activeTaskChangedCalls).isEqualTo(2)
+ }
+
+ @Test
+ fun removeActiveTask_listenerNotifiedAndTaskNotActive() {
+ val listener = TestListener()
+ repo.addListener(listener)
+
+ repo.addActiveTask(1)
+ repo.removeActiveTask(1)
+ // Notify once for add and once for remove
+ assertThat(listener.activeTaskChangedCalls).isEqualTo(2)
+ assertThat(repo.isActiveTask(1)).isFalse()
+ }
+
+ @Test
+ fun removeActiveTask_removeNotExistingTaskDoesNotNotify() {
+ val listener = TestListener()
+ repo.addListener(listener)
+ repo.removeActiveTask(99)
+ assertThat(listener.activeTaskChangedCalls).isEqualTo(0)
+ }
+
+ @Test
+ fun isActiveTask_notExistingTaskReturnsFalse() {
+ assertThat(repo.isActiveTask(99)).isFalse()
+ }
+
+ class TestListener : DesktopModeTaskRepository.Listener {
+ var activeTaskChangedCalls = 0
+ override fun onActiveTasksChanged() {
+ activeTaskChangedCalls++
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index e9a1e25..cadfeb0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -55,6 +55,7 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.desktopmode.DesktopMode;
+import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.util.GroupedRecentTaskInfo;
@@ -82,6 +83,8 @@
private TaskStackListenerImpl mTaskStackListener;
@Mock
private ShellCommandHandler mShellCommandHandler;
+ @Mock
+ private DesktopModeTaskRepository mDesktopModeTaskRepository;
private ShellTaskOrganizer mShellTaskOrganizer;
private RecentTasksController mRecentTasksController;
@@ -94,7 +97,8 @@
when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
mShellInit = spy(new ShellInit(mMainExecutor));
mRecentTasksController = spy(new RecentTasksController(mContext, mShellInit,
- mShellCommandHandler, mTaskStackListener, mMainExecutor));
+ mShellCommandHandler, mTaskStackListener, Optional.of(mDesktopModeTaskRepository),
+ mMainExecutor));
mShellTaskOrganizer = new ShellTaskOrganizer(mShellInit, mShellCommandHandler,
null /* sizeCompatUI */, Optional.empty(), Optional.of(mRecentTasksController),
mMainExecutor);
@@ -195,8 +199,8 @@
ActivityManager.RecentTaskInfo t4 = makeTaskInfo(4);
setRawList(t1, t2, t3, t4);
- mRecentTasksController.addActiveFreeformTask(1);
- mRecentTasksController.addActiveFreeformTask(3);
+ when(mDesktopModeTaskRepository.isActiveTask(1)).thenReturn(true);
+ when(mDesktopModeTaskRepository.isActiveTask(3)).thenReturn(true);
ArrayList<GroupedRecentTaskInfo> recentTasks = mRecentTasksController.getRecentTasks(
MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index a5f3df9..7927c5d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -81,8 +81,10 @@
private int mDeviceMode;
private long mHiSyncId;
private int mGroupId;
+
// Need this since there is no method for getting RSSI
short mRssi;
+
// mProfiles and mRemovedProfiles does not do swap() between main and sub device. It is
// because current sub device is only for HearingAid and its profile is the same.
private final Collection<LocalBluetoothProfile> mProfiles = new CopyOnWriteArrayList<>();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java
new file mode 100644
index 0000000..feb5e0b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java
@@ -0,0 +1,73 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.util.HashMap;
+
+/** Utils class to report hearing aid metrics to statsd */
+public final class HearingAidStatsLogUtils {
+
+ private static final String TAG = "HearingAidStatsLogUtils";
+ private static final HashMap<String, Integer> sDeviceAddressToBondEntryMap = new HashMap<>();
+
+ /**
+ * Sets the mapping from hearing aid device to the bond entry where this device starts it's
+ * bonding(connecting) process.
+ *
+ * @param bondEntry The entry page id where the bonding process starts
+ * @param device The bonding(connecting) hearing aid device
+ */
+ public static void setBondEntryForDevice(int bondEntry, CachedBluetoothDevice device) {
+ sDeviceAddressToBondEntryMap.put(device.getAddress(), bondEntry);
+ }
+
+ /**
+ * Logs hearing aid device information to westworld, including device mode, device side, and
+ * entry page id where the binding(connecting) process starts.
+ *
+ * Only logs the info once after hearing aid is bonded(connected). Clears the map entry of this
+ * device when logging is completed.
+ *
+ * @param device The bonded(connected) hearing aid device
+ */
+ public static void logHearingAidInfo(CachedBluetoothDevice device) {
+ final String deviceAddress = device.getAddress();
+ if (sDeviceAddressToBondEntryMap.containsKey(deviceAddress)) {
+ final int bondEntry = sDeviceAddressToBondEntryMap.getOrDefault(deviceAddress, -1);
+ final int deviceMode = device.getDeviceMode();
+ final int deviceSide = device.getDeviceSide();
+ FrameworkStatsLog.write(FrameworkStatsLog.HEARING_AID_INFO_REPORTED, deviceMode,
+ deviceSide, bondEntry);
+
+ sDeviceAddressToBondEntryMap.remove(deviceAddress);
+ } else {
+ Log.w(TAG, "The device address was not found. Hearing aid device info is not logged.");
+ }
+ }
+
+ @VisibleForTesting
+ static HashMap<String, Integer> getDeviceAddressToBondEntryMap() {
+ return sDeviceAddressToBondEntryMap;
+ }
+
+ private HearingAidStatsLogUtils() {}
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 4714ff9..8a9f9dd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -352,6 +352,8 @@
cachedDevice.setHiSyncId(newHiSyncId);
}
}
+
+ HearingAidStatsLogUtils.logHearingAidInfo(cachedDevice);
}
if (getCsipSetCoordinatorProfile() != null
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java
new file mode 100644
index 0000000..0cf5b89
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.HashMap;
+
+@RunWith(RobolectricTestRunner.class)
+public class HearingAidStatsLogUtilsTest {
+
+ private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
+
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
+ @Mock
+ private CachedBluetoothDevice mCachedBluetoothDevice;
+
+ @Test
+ public void setBondEntryForDevice_addsEntryToDeviceAddressToBondEntryMap() {
+ when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
+
+ HearingAidStatsLogUtils.setBondEntryForDevice(
+ FrameworkStatsLog.HEARING_AID_INFO_REPORTED__BOND_ENTRY__BLUETOOTH,
+ mCachedBluetoothDevice);
+
+ final HashMap<String, Integer> map =
+ HearingAidStatsLogUtils.getDeviceAddressToBondEntryMap();
+ assertThat(map.containsKey(TEST_DEVICE_ADDRESS)).isTrue();
+ assertThat(map.get(TEST_DEVICE_ADDRESS)).isEqualTo(
+ FrameworkStatsLog.HEARING_AID_INFO_REPORTED__BOND_ENTRY__BLUETOOTH);
+ }
+
+ @Test
+ public void logHearingAidInfo_removesEntryFromDeviceAddressToBondEntryMap() {
+ when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
+
+ HearingAidStatsLogUtils.setBondEntryForDevice(
+ FrameworkStatsLog.HEARING_AID_INFO_REPORTED__BOND_ENTRY__BLUETOOTH,
+ mCachedBluetoothDevice);
+ HearingAidStatsLogUtils.logHearingAidInfo(mCachedBluetoothDevice);
+
+ final HashMap<String, Integer> map =
+ HearingAidStatsLogUtils.getDeviceAddressToBondEntryMap();
+ assertThat(map.containsKey(TEST_DEVICE_ADDRESS)).isFalse();
+ }
+}
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten1.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten1.jpeg
new file mode 100644
index 0000000..6241b0b
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable/kitten1.jpeg
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten2.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten2.jpeg
new file mode 100644
index 0000000..870ef13
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable/kitten2.jpeg
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten3.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten3.jpeg
new file mode 100644
index 0000000..bb7261c
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable/kitten3.jpeg
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten4.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten4.jpeg
new file mode 100644
index 0000000..e34b7dd
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable/kitten4.jpeg
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten5.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten5.jpeg
new file mode 100644
index 0000000..9cde24b
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable/kitten5.jpeg
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten6.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten6.jpeg
new file mode 100644
index 0000000..17825b6
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable/kitten6.jpeg
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
index 2e6456b..6805bf8 100644
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
@@ -28,25 +28,25 @@
/** The gallery app screens. */
object GalleryAppScreens {
- val Typography = ChildScreen("typography") { TypographyScreen() }
- val MaterialColors = ChildScreen("material_colors") { MaterialColorsScreen() }
- val AndroidColors = ChildScreen("android_colors") { AndroidColorsScreen() }
- val Buttons = ChildScreen("buttons") { ButtonsScreen() }
- val ExampleFeature = ChildScreen("example_feature") { ExampleFeatureScreen() }
+ private val Typography = ChildScreen("typography") { TypographyScreen() }
+ private val MaterialColors = ChildScreen("material_colors") { MaterialColorsScreen() }
+ private val AndroidColors = ChildScreen("android_colors") { AndroidColorsScreen() }
+ private val Buttons = ChildScreen("buttons") { ButtonsScreen() }
+ private val ExampleFeature = ChildScreen("example_feature") { ExampleFeatureScreen() }
- val PeopleEmpty =
+ private val PeopleEmpty =
ChildScreen("people_empty") { navController ->
EmptyPeopleScreen(onResult = { navController.popBackStack() })
}
- val PeopleFew =
+ private val PeopleFew =
ChildScreen("people_few") { navController ->
FewPeopleScreen(onResult = { navController.popBackStack() })
}
- val PeopleFull =
+ private val PeopleFull =
ChildScreen("people_full") { navController ->
FullPeopleScreen(onResult = { navController.popBackStack() })
}
- val People =
+ private val People =
ParentScreen(
"people",
mapOf(
@@ -55,6 +55,52 @@
"Full" to PeopleFull,
)
)
+ private val UserSwitcherSingleUser =
+ ChildScreen("user_switcher_single") { navController ->
+ UserSwitcherScreen(
+ userCount = 1,
+ onFinished = navController::popBackStack,
+ )
+ }
+ private val UserSwitcherThreeUsers =
+ ChildScreen("user_switcher_three") { navController ->
+ UserSwitcherScreen(
+ userCount = 3,
+ onFinished = navController::popBackStack,
+ )
+ }
+ private val UserSwitcherFourUsers =
+ ChildScreen("user_switcher_four") { navController ->
+ UserSwitcherScreen(
+ userCount = 4,
+ onFinished = navController::popBackStack,
+ )
+ }
+ private val UserSwitcherFiveUsers =
+ ChildScreen("user_switcher_five") { navController ->
+ UserSwitcherScreen(
+ userCount = 5,
+ onFinished = navController::popBackStack,
+ )
+ }
+ private val UserSwitcherSixUsers =
+ ChildScreen("user_switcher_six") { navController ->
+ UserSwitcherScreen(
+ userCount = 6,
+ onFinished = navController::popBackStack,
+ )
+ }
+ private val UserSwitcher =
+ ParentScreen(
+ "user_switcher",
+ mapOf(
+ "Single" to UserSwitcherSingleUser,
+ "Three" to UserSwitcherThreeUsers,
+ "Four" to UserSwitcherFourUsers,
+ "Five" to UserSwitcherFiveUsers,
+ "Six" to UserSwitcherSixUsers,
+ )
+ )
val Home =
ParentScreen(
@@ -66,6 +112,7 @@
"Example feature" to ExampleFeature,
"Buttons" to Buttons,
"People" to People,
+ "User Switcher" to UserSwitcher,
)
)
}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/UserSwitcherScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/UserSwitcherScreen.kt
new file mode 100644
index 0000000..fe9707d
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/UserSwitcherScreen.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.compose.gallery
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+import com.android.systemui.user.Fakes.fakeUserSwitcherViewModel
+import com.android.systemui.user.ui.compose.UserSwitcherScreen
+
+@Composable
+fun UserSwitcherScreen(
+ userCount: Int,
+ onFinished: () -> Unit,
+) {
+ val context = LocalContext.current.applicationContext
+ UserSwitcherScreen(
+ viewModel = fakeUserSwitcherViewModel(context, userCount = userCount),
+ onFinished = onFinished,
+ )
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt
index 02d76f4..91a73ea 100644
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt
@@ -58,12 +58,29 @@
(0 until userCount).map { index ->
UserModel(
id = index,
- name = Text.Loaded("user_$index"),
+ name =
+ Text.Loaded(
+ when (index % 6) {
+ 0 -> "Ross Geller"
+ 1 -> "Phoebe Buffay"
+ 2 -> "Monica Geller"
+ 3 -> "Rachel Greene"
+ 4 -> "Chandler Bing"
+ else -> "Joey Tribbiani"
+ }
+ ),
image =
checkNotNull(
AppCompatResources.getDrawable(
context,
- R.drawable.ic_avatar_guest_user
+ when (index % 6) {
+ 0 -> R.drawable.kitten1
+ 1 -> R.drawable.kitten2
+ 2 -> R.drawable.kitten3
+ 3 -> R.drawable.kitten4
+ 4 -> R.drawable.kitten5
+ else -> R.drawable.kitten6
+ },
)
),
isSelected = index == 0,
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_invert_colors_icon_off.xml b/packages/SystemUI/res-keyguard/drawable/qs_invert_colors_icon_off.xml
new file mode 100644
index 0000000..a347123
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_invert_colors_icon_off.xml
@@ -0,0 +1,109 @@
+<?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="17"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M7.38 -0.28 C5.69,-2.81 1.5,-8.5 0.01,-7.32 C0.03,-6.22 -0.06,6.16 -0.06,7.78 C1.56,7.81 5.44,7.19 7.37,2.06 C7.37,1.21 7.35,1.69 7.35,1 C7.35,0.09 7.38,0.59 7.38,-0.28c "
+ android:valueTo="M6 -2.38 C1.81,-6.69 -0.5,-10 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 3,7.75 5.47,4.91 C6.33,3.91 7.21,2.42 7.24,1.13 C7.26,-0.05 6.87,-1.49 6,-2.38c "
+ 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="33"
+ android:propertyName="pathData"
+ android:startOffset="17"
+ android:valueFrom="M6 -2.38 C1.81,-6.69 -0.5,-10 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 3,7.75 5.47,4.91 C6.33,3.91 7.21,2.42 7.24,1.13 C7.26,-0.05 6.87,-1.49 6,-2.38c "
+ android:valueTo="M4.94 -3.95 C-0.31,-9.06 0.52,-9.42 -5.75,-3.22 C-8.31,-0.69 -7.05,3 -6.94,3.22 C-3.63,9.31 2.63,9.5 5.94,4.59 C6.61,3.6 7.43,1.16 7.12,0 C6.72,-1.45 6.01,-2.9 4.94,-3.95c "
+ 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="50"
+ android:valueFrom="M4.94 -3.95 C-0.31,-9.06 0.52,-9.42 -5.75,-3.22 C-8.31,-0.69 -7.05,3 -6.94,3.22 C-3.63,9.31 2.63,9.5 5.94,4.59 C6.61,3.6 7.43,1.16 7.12,0 C6.72,-1.45 6.01,-2.9 4.94,-3.95c "
+ android:valueTo="M3.07 -5.83 C-0.44,-10.25 -2.56,-6.87 -6.11,-2.6 C-7.03,-1.49 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.1,-4.1 3.07,-5.83c "
+ 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="117"
+ android:valueFrom="M3.07 -5.83 C-0.44,-10.25 -2.56,-6.87 -6.11,-2.6 C-7.03,-1.49 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.1,-4.1 3.07,-5.83c "
+ android:valueTo="M0 -8.18 C-1.81,-7.06 -3.89,-5.21 -5.95,-2.81 C-7.56,-0.94 -7.37,0.88 -7.37,1.09 C-7.37,6.31 -2.19,7.99 0,7.99 C0,6.34 -0.01,3.91 -0.01,0 C-0.01,-3.91 0,-6 0,-8.18c "
+ 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="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="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M7.38 -0.28 C5.69,-2.81 1.5,-8.5 0.01,-7.32 C0.03,-6.22 -0.06,6.16 -0.06,7.78 C1.56,7.81 5.44,7.19 7.37,2.06 C7.37,1.21 7.35,1.69 7.35,1 C7.35,0.09 7.38,0.59 7.38,-0.28c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M0 -7.19 C0,-7.19 2.93,-4.32 4.38,-2.87 C5.25,-2 5.88,-0.62 5.88,1.19 C5.88,4.5 2.8,6.97 0,7 C-2.8,7.03 -6,4.37 -6,1.13 C-6,-0.43 -5.38,-1.9 -4.25,-3.01 C-4.25,-3.01 0,-7.19 0,-7.19 M-5.65 -4.44 C-5.65,-4.44 -5.65,-4.44 -5.65,-4.44 C-7.1,-3.01 -8,-1.04 -8,1.13 C-8,5.48 -4.42,9 0,9 C4.42,9 8,5.48 8,1.13 C8,-1.04 7.1,-3.01 5.65,-4.44 C5.65,-4.44 5.65,-4.44 5.65,-4.44 C5.65,-4.44 0,-10 0,-10 C0,-10 -5.65,-4.44 -5.65,-4.44c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_invert_colors_icon_on.xml b/packages/SystemUI/res-keyguard/drawable/qs_invert_colors_icon_on.xml
new file mode 100644
index 0000000..c5609d8
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_invert_colors_icon_on.xml
@@ -0,0 +1,109 @@
+<?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="100"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M0 -7.49 C-2.58,-7.49 -7.47,-2.59 -7.47,0.57 C-7.47,0.77 -7.37,0.88 -7.37,1.09 C-7.37,6.31 -2.19,7.55 0,7.55 C0,5.91 -0.01,3.91 -0.01,0 C-0.01,-3.91 0,-5.31 0,-7.49c "
+ android:valueTo="M3.11 -6.83 C-1.37,-10.12 -6.04,-3.87 -7.22,0.09 C-7.26,0.29 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.14,-5.1 3.11,-6.83c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="pathData"
+ android:startOffset="100"
+ android:valueFrom="M3.11 -6.83 C-1.37,-10.12 -6.04,-3.87 -7.22,0.09 C-7.26,0.29 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.14,-5.1 3.11,-6.83c "
+ android:valueTo="M5 -3.95 C-0.25,-9.87 -0.47,-8.74 -5,-3.63 C-7.94,-0.31 -7.05,3 -6.94,3.22 C-3.63,9.31 2.94,9.19 7,3.59 C7.06,1.94 7,3.19 7.12,0 C7.19,-2 5.06,-2.75 5,-3.95c "
+ 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="167"
+ android:valueFrom="M5 -3.95 C-0.25,-9.87 -0.47,-8.74 -5,-3.63 C-7.94,-0.31 -7.05,3 -6.94,3.22 C-3.63,9.31 2.94,9.19 7,3.59 C7.06,1.94 7,3.19 7.12,0 C7.19,-2 5.06,-2.75 5,-3.95c "
+ android:valueTo="M4.82 -3.81 C1,-7.87 0.75,-9.37 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 4.38,7.38 6.4,3.22 C6.77,2.46 7,1.69 6.74,0 C6.56,-1.16 5.85,-2.71 4.82,-3.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>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="pathData"
+ android:startOffset="233"
+ android:valueFrom="M4.82 -3.81 C1,-7.87 0.75,-9.37 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 4.38,7.38 6.4,3.22 C6.77,2.46 7,1.69 6.74,0 C6.56,-1.16 5.85,-2.71 4.82,-3.81c "
+ android:valueTo="M5.63 -2.97 C3.65,-4.93 0.75,-8.37 0.01,-7.32 C0.03,-6.22 -0.03,5.66 -0.03,7.28 C1.59,7.31 4.13,7.94 6.31,3.44 C6.68,2.66 7,1.37 6.87,0.06 C6.77,-0.84 6.13,-2.47 5.63,-2.97c "
+ 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="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="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M0 -7.49 C-2.58,-7.49 -7.47,-2.59 -7.47,0.57 C-7.47,0.77 -7.37,0.88 -7.37,1.09 C-7.37,6.31 -2.19,7.55 0,7.55 C0,5.91 -0.01,3.91 -0.01,0 C-0.01,-3.91 0,-5.31 0,-7.49c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M0 -7.19 C0,-7.19 2.93,-4.32 4.38,-2.87 C5.25,-2 5.88,-0.62 5.88,1.19 C5.88,4.5 2.8,6.97 0,7 C-2.8,7.03 -6,4.37 -6,1.13 C-6,-0.43 -5.38,-1.9 -4.25,-3.01 C-4.25,-3.01 0,-7.19 0,-7.19 M-5.65 -4.44 C-5.65,-4.44 -5.65,-4.44 -5.65,-4.44 C-7.1,-3.01 -8,-1.04 -8,1.13 C-8,5.48 -4.42,9 0,9 C4.42,9 8,5.48 8,1.13 C8,-1.04 7.1,-3.01 5.65,-4.44 C5.65,-4.44 5.65,-4.44 5.65,-4.44 C5.65,-4.44 0,-10 0,-10 C0,-10 -5.65,-4.44 -5.65,-4.44c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/qs_airplane_icon_off.xml b/packages/SystemUI/res/drawable/qs_airplane_icon_off.xml
index f239a8d..420ae70 100644
--- a/packages/SystemUI/res/drawable/qs_airplane_icon_off.xml
+++ b/packages/SystemUI/res/drawable/qs_airplane_icon_off.xml
@@ -15,11 +15,45 @@
-->
<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="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#000000"
+ android:valueTo="#ffffff"
+ android:valueType="colorType">
+ <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_0_P_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#000000"
+ android:valueTo="#ffffff"
+ android:valueType="colorType">
+ <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="time_group">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="183"
+ android:duration="333"
android:propertyName="translateX"
android:startOffset="0"
android:valueFrom="0"
@@ -38,13 +72,29 @@
<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=" M-1.5 -3.02 C-1.5,-3.02 -1.5,-8.5 -1.5,-8.5 C-1.5,-9.33 -0.83,-10 0,-10 C0.83,-10 1.5,-9.33 1.5,-8.5 C1.5,-8.5 1.5,-3 1.5,-3 C1.5,-3 10,2 10,2 C10,2 10,4 10,4 C10,4 1.51,1.49 1.51,1.49 C1.51,1.49 -1.5,-3.02 -1.5,-3.02c M1.5 1.5 C1.5,1.5 -1.5,-3 -1.5,-3 C-1.5,-3 -10,2 -10,2 C-10,2 -10,4 -10,4 C-10,4 -1.5,1.5 -1.5,1.5 C-1.5,1.5 -1.5,7 -1.5,7 C-1.5,7 -4,8.5 -4,8.5 C-4,8.5 -4,10 -4,10 C-4,10 0,9 0,9 C0,9 4,10 4,10 C4,10 4,8.5 4,8.5 C4,8.5 1.5,7 1.5,7 C1.5,7 1.5,1.5 1.5,1.5c " />
+ android:translateY="12.469">
+ <group
+ android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:pathData=" M-1.5 -3.02 C-1.5,-3.02 -1.5,-8.5 -1.5,-8.5 C-1.5,-9.33 -0.83,-10 0,-10 C0.83,-10 1.5,-9.33 1.5,-8.5 C1.5,-8.5 1.5,-3 1.5,-3 C1.5,-3 10,2 10,2 C10,2 10,4 10,4 C10,4 1.51,1.49 1.51,1.49 C1.51,1.49 -1.5,-3.02 -1.5,-3.02c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_1"
+ android:fillAlpha="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:pathData=" M1.51 1.5 C1.51,1.5 -1.5,-3.02 -1.5,-3.02 C-1.5,-3.02 -10,2 -10,2 C-10,2 -10,4 -10,4 C-10,4 -1.5,1.5 -1.5,1.5 C-1.5,1.5 -1.5,7 -1.5,7 C-1.5,7 -4,8.5 -4,8.5 C-4,8.5 -4,10 -4,10 C-4,10 0,9 0,9 C0,9 4,10 4,10 C4,10 4,8.5 4,8.5 C4,8.5 1.5,7 1.5,7 C1.5,7 1.51,1.5 1.51,1.5c " />
+ </group>
</group>
</group>
<group android:name="time_group" />
diff --git a/packages/SystemUI/res/drawable/qs_airplane_icon_on.xml b/packages/SystemUI/res/drawable/qs_airplane_icon_on.xml
index d46fafa..57d7902 100644
--- a/packages/SystemUI/res/drawable/qs_airplane_icon_on.xml
+++ b/packages/SystemUI/res/drawable/qs_airplane_icon_on.xml
@@ -15,35 +15,213 @@
-->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
- <target android:name="_R_G_L_1_G">
+ <target android:name="_R_G_L_0_G_D_0_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="667"
- android:pathData="M 12.125,34.75C 12.104,30.958 12.021,15.792 12,12"
- android:propertyName="translateXY"
- android:propertyXName="translateX"
- android:propertyYName="translateY"
- android:startOffset="0">
+ android:duration="250"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#ffffff"
+ android:valueTo="#000000"
+ android:valueType="colorType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.1,1 1.0,1.0" />
+ <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">
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="517"
- android:pathData="M 12,12C 12.021,8.312 12.104,-6.436999999999999 12.125,-10.125"
- android:propertyName="translateXY"
- android:propertyXName="translateX"
- android:propertyYName="translateY"
- android:startOffset="0">
+ android:duration="383"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1.1500000000000001"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.1,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.4,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="383"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1.1500000000000001"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.4,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="767"
+ android:propertyName="scaleX"
+ android:startOffset="383"
+ android:valueFrom="1.1500000000000001"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.199,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="767"
+ android:propertyName="scaleY"
+ android:startOffset="383"
+ android:valueFrom="1.1500000000000001"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.199,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M-1.5 -3.02 C-1.5,-3.02 -1.5,-8.5 -1.5,-8.5 C-1.5,-9.33 -0.83,-10 0,-10 C0.83,-10 1.5,-9.33 1.5,-8.5 C1.5,-8.5 1.5,-3 1.5,-3 C1.5,-3 10,2 10,2 C10,2 10,4 10,4 C10,4 1.51,1.49 1.51,1.49 C1.51,1.49 -1.5,-3.02 -1.5,-3.02c "
+ android:valueTo="M-1.74 -2.93 C-1.74,-2.93 -2.06,-7.3 -2.06,-7.3 C-2.14,-8.99 -1.15,-10 0,-10 C1.15,-10 2.08,-8.88 2.09,-7.3 C2.09,-7.3 1.74,-3.09 1.74,-3.09 C1.74,-3.09 9.44,2.79 9.44,2.79 C9.44,2.79 9.44,4.79 9.44,4.79 C9.44,4.79 1.69,1.57 1.69,1.57 C1.69,1.57 -1.74,-2.93 -1.74,-2.93c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="pathData"
+ android:startOffset="200"
+ android:valueFrom="M-1.74 -2.93 C-1.74,-2.93 -2.06,-7.3 -2.06,-7.3 C-2.14,-8.99 -1.15,-10 0,-10 C1.15,-10 2.08,-8.88 2.09,-7.3 C2.09,-7.3 1.74,-3.09 1.74,-3.09 C1.74,-3.09 9.44,2.79 9.44,2.79 C9.44,2.79 9.44,4.79 9.44,4.79 C9.44,4.79 1.69,1.57 1.69,1.57 C1.69,1.57 -1.74,-2.93 -1.74,-2.93c "
+ android:valueTo="M-1.5 -3.02 C-1.5,-3.02 -1.5,-8.5 -1.5,-8.5 C-1.5,-9.33 -0.83,-10 0,-10 C0.83,-10 1.5,-9.33 1.5,-8.5 C1.5,-8.5 1.5,-3 1.5,-3 C1.5,-3 10,2 10,2 C10,2 10,4 10,4 C10,4 1.51,1.49 1.51,1.49 C1.51,1.49 -1.5,-3.02 -1.5,-3.02c "
+ 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="217"
+ android:propertyName="pathData"
+ android:startOffset="417"
+ android:valueFrom="M-1.5 -3.02 C-1.5,-3.02 -1.5,-8.5 -1.5,-8.5 C-1.5,-9.33 -0.83,-10 0,-10 C0.83,-10 1.5,-9.33 1.5,-8.5 C1.5,-8.5 1.5,-3 1.5,-3 C1.5,-3 10,2 10,2 C10,2 10,4 10,4 C10,4 1.51,1.49 1.51,1.49 C1.51,1.49 -1.5,-3.02 -1.5,-3.02c "
+ android:valueTo="M-1.5 -3.02 C-1.5,-3.02 -1.5,-8.5 -1.5,-8.5 C-1.5,-9.33 -0.83,-10 0,-10 C0.83,-10 1.5,-9.33 1.5,-8.5 C1.5,-8.5 1.5,-3 1.5,-3 C1.5,-3 10,2 10,2 C10,2 10,4 10,4 C10,4 1.51,1.49 1.51,1.49 C1.51,1.49 -1.5,-3.02 -1.5,-3.02c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.35,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#ffffff"
+ android:valueTo="#000000"
+ android:valueType="colorType">
+ <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_0_P_1_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="383"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1.1500000000000001"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.4,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="383"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1.1500000000000001"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.4,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="767"
+ android:propertyName="scaleX"
+ android:startOffset="383"
+ android:valueFrom="1.1500000000000001"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.199,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="767"
+ android:propertyName="scaleY"
+ android:startOffset="383"
+ android:valueFrom="1.1500000000000001"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.6,0 0.199,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M1.51 1.49 C1.51,1.49 -1.5,-3.02 -1.5,-3.02 C-1.5,-3.02 -10,2 -10,2 C-10,2 -10,4 -10,4 C-10,4 -1.5,1.5 -1.5,1.5 C-1.5,1.5 -1.5,7 -1.5,7 C-1.5,7 -4,8.5 -4,8.5 C-4,8.5 -4,10 -4,10 C-4,10 0,9 0,9 C0,9 4,10 4,10 C4,10 4,8.5 4,8.5 C4,8.5 1.5,7 1.5,7 C1.5,7 1.51,1.49 1.51,1.49c "
+ android:valueTo="M1.69 1.58 C1.69,1.58 -1.74,-2.92 -1.74,-2.92 C-1.74,-2.92 -9.44,2.79 -9.44,2.79 C-9.44,2.79 -9.44,4.79 -9.44,4.79 C-9.44,4.79 -1.67,1.42 -1.67,1.42 C-1.67,1.42 -1.11,7.28 -1.11,7.28 C-1.11,7.28 -2.94,8.78 -2.94,8.78 C-2.94,8.78 -2.92,10 -2.92,10 C-2.92,10 0,9 0,9 C0,9 2.92,10 2.92,10 C2.92,10 2.91,8.78 2.91,8.78 C2.91,8.78 1.08,7.28 1.08,7.28 C1.08,7.28 1.69,1.58 1.69,1.58c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="pathData"
+ android:startOffset="200"
+ android:valueFrom="M1.69 1.58 C1.69,1.58 -1.74,-2.92 -1.74,-2.92 C-1.74,-2.92 -9.44,2.79 -9.44,2.79 C-9.44,2.79 -9.44,4.79 -9.44,4.79 C-9.44,4.79 -1.67,1.42 -1.67,1.42 C-1.67,1.42 -1.11,7.28 -1.11,7.28 C-1.11,7.28 -2.94,8.78 -2.94,8.78 C-2.94,8.78 -2.92,10 -2.92,10 C-2.92,10 0,9 0,9 C0,9 2.92,10 2.92,10 C2.92,10 2.91,8.78 2.91,8.78 C2.91,8.78 1.08,7.28 1.08,7.28 C1.08,7.28 1.69,1.58 1.69,1.58c "
+ android:valueTo="M1.51 1.5 C1.51,1.5 -1.5,-3.02 -1.5,-3.02 C-1.5,-3.02 -10,2 -10,2 C-10,2 -10,4 -10,4 C-10,4 -1.5,1.5 -1.5,1.5 C-1.5,1.5 -1.5,7 -1.5,7 C-1.5,7 -4,8.5 -4,8.5 C-4,8.5 -4,10 -4,10 C-4,10 0,9 0,9 C0,9 4,10 4,10 C4,10 4,8.5 4,8.5 C4,8.5 1.5,7 1.5,7 C1.5,7 1.51,1.5 1.51,1.5c "
+ 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="217"
+ android:propertyName="pathData"
+ android:startOffset="417"
+ android:valueFrom="M1.51 1.5 C1.51,1.5 -1.5,-3.02 -1.5,-3.02 C-1.5,-3.02 -10,2 -10,2 C-10,2 -10,4 -10,4 C-10,4 -1.5,1.5 -1.5,1.5 C-1.5,1.5 -1.5,7 -1.5,7 C-1.5,7 -4,8.5 -4,8.5 C-4,8.5 -4,10 -4,10 C-4,10 0,9 0,9 C0,9 4,10 4,10 C4,10 4,8.5 4,8.5 C4,8.5 1.5,7 1.5,7 C1.5,7 1.51,1.5 1.51,1.5c "
+ android:valueTo="M1.51 1.5 C1.51,1.5 -1.5,-3.02 -1.5,-3.02 C-1.5,-3.02 -10,2 -10,2 C-10,2 -10,4 -10,4 C-10,4 -1.5,1.5 -1.5,1.5 C-1.5,1.5 -1.5,7 -1.5,7 C-1.5,7 -4,8.5 -4,8.5 C-4,8.5 -4,10 -4,10 C-4,10 0,9 0,9 C0,9 4,10 4,10 C4,10 4,8.5 4,8.5 C4,8.5 1.5,7 1.5,7 C1.5,7 1.51,1.5 1.51,1.5c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.35,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
@@ -53,7 +231,7 @@
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="683"
+ android:duration="1167"
android:propertyName="translateX"
android:startOffset="0"
android:valueFrom="0"
@@ -70,26 +248,31 @@
android:viewportWidth="24">
<group android:name="_R_G">
<group
- android:name="_R_G_L_1_G"
- android:translateX="12.125"
- android:translateY="34.75">
- <path
- android:name="_R_G_L_1_G_D_0_P_0"
- android:fillAlpha="1"
- android:fillColor="#ffffff"
- android:fillType="nonZero"
- android:pathData=" M10 4 C10,4 10,2 10,2 C10,2 1.5,-3 1.5,-3 C1.5,-3 1.5,-8.5 1.5,-8.5 C1.5,-9.33 0.83,-10 0,-10 C-0.83,-10 -1.5,-9.33 -1.5,-8.5 C-1.5,-8.5 -1.5,-3 -1.5,-3 C-1.5,-3 -10,2 -10,2 C-10,2 -10,4 -10,4 C-10,4 -1.5,1.5 -1.5,1.5 C-1.5,1.5 -1.5,7 -1.5,7 C-1.5,7 -4,8.5 -4,8.5 C-4,8.5 -4,10 -4,10 C-4,10 0,9 0,9 C0,9 4,10 4,10 C4,10 4,8.5 4,8.5 C4,8.5 1.5,7 1.5,7 C1.5,7 1.5,1.5 1.5,1.5 C1.5,1.5 10,4 10,4c " />
- </group>
- <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=" M-1.5 -3.02 C-1.5,-3.02 -1.5,-8.5 -1.5,-8.5 C-1.5,-9.33 -0.83,-10 0,-10 C0.83,-10 1.5,-9.33 1.5,-8.5 C1.5,-8.5 1.5,-3 1.5,-3 C1.5,-3 10,2 10,2 C10,2 10,4 10,4 C10,4 1.51,1.49 1.51,1.49 C1.51,1.49 -1.5,-3.02 -1.5,-3.02c M1.5 1.5 C1.5,1.5 -1.5,-3 -1.5,-3 C-1.5,-3 -10,2 -10,2 C-10,2 -10,4 -10,4 C-10,4 -1.5,1.5 -1.5,1.5 C-1.5,1.5 -1.5,7 -1.5,7 C-1.5,7 -4,8.5 -4,8.5 C-4,8.5 -4,10 -4,10 C-4,10 0,9 0,9 C0,9 4,10 4,10 C4,10 4,8.5 4,8.5 C4,8.5 1.5,7 1.5,7 C1.5,7 1.5,1.5 1.5,1.5c " />
+ android:translateY="12.469">
+ <group
+ android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M-1.5 -3.02 C-1.5,-3.02 -1.5,-8.5 -1.5,-8.5 C-1.5,-9.33 -0.83,-10 0,-10 C0.83,-10 1.5,-9.33 1.5,-8.5 C1.5,-8.5 1.5,-3 1.5,-3 C1.5,-3 10,2 10,2 C10,2 10,4 10,4 C10,4 1.51,1.49 1.51,1.49 C1.51,1.49 -1.5,-3.02 -1.5,-3.02c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0"
+ android:scaleX="1"
+ android:scaleY="1">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_1"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M1.51 1.49 C1.51,1.49 -1.5,-3.02 -1.5,-3.02 C-1.5,-3.02 -10,2 -10,2 C-10,2 -10,4 -10,4 C-10,4 -1.5,1.5 -1.5,1.5 C-1.5,1.5 -1.5,7 -1.5,7 C-1.5,7 -4,8.5 -4,8.5 C-4,8.5 -4,10 -4,10 C-4,10 0,9 0,9 C0,9 4,10 4,10 C4,10 4,8.5 4,8.5 C4,8.5 1.5,7 1.5,7 C1.5,7 1.51,1.49 1.51,1.49c " />
+ </group>
</group>
</group>
<group android:name="time_group" />
diff --git a/packages/SystemUI/res/drawable/qs_extra_dim_icon_off.xml b/packages/SystemUI/res/drawable/qs_extra_dim_icon_off.xml
new file mode 100644
index 0000000..b0f85e7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_extra_dim_icon_off.xml
@@ -0,0 +1,197 @@
+<?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_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="350"
+ android:propertyName="strokeColor"
+ android:startOffset="0"
+ android:valueFrom="#000000"
+ android:valueTo="#ffffff"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="350"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#000000"
+ android:valueTo="#ffffff"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="350"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M93 39.5 C93,39.55 93,41.52 93,44 C93,46.49 93,48.58 93,48.5 C90.52,48.5 88.5,46.49 88.5,44 C88.5,41.52 90.52,39.5 93,39.5c M94 37 C94,37 92,37 92,37 C92,37 92,35.44 92,35.44 C92,35.44 94,35.44 94,35.44 C94,35.44 94,37 94,37c M86 43 C86,43 86,45 86,45 C86,45 84.31,45 84.31,45 C84.31,45 84.31,43 84.31,43 C84.31,43 86,43 86,43c M92 51 C92,51 94,51 94,51 C94,51 94,52.69 94,52.69 C94,52.69 92,52.69 92,52.69 C92,52.69 92,51 92,51c M100 45 C100,45 100,43 100,43 C100,43 101.75,43 101.75,43 C101.75,43 101.75,45 101.75,45 C101.75,45 100,45 100,45c M86.07 38.57 C86.07,38.57 87.48,37.16 87.48,37.16 C87.48,37.16 88.76,38.34 88.76,38.34 C88.76,38.34 87.34,39.76 87.34,39.76 C87.34,39.76 86.07,38.57 86.07,38.57c M87.57 50.87 C87.57,50.87 86.16,49.46 86.16,49.46 C86.16,49.46 87.34,48.24 87.34,48.24 C87.34,48.24 88.76,49.66 88.76,49.66 C88.76,49.66 87.57,50.87 87.57,50.87c M99.9 49.43 C99.9,49.43 98.49,50.84 98.49,50.84 C98.49,50.84 97.24,49.66 97.24,49.66 C97.24,49.66 98.66,48.24 98.66,48.24 C98.66,48.24 99.9,49.43 99.9,49.43c M98.52 37.13 C98.52,37.13 99.93,38.54 99.93,38.54 C99.93,38.54 98.66,39.76 98.66,39.76 C98.66,39.76 97.24,38.34 97.24,38.34 C97.24,38.34 98.52,37.13 98.52,37.13c "
+ android:valueTo="M93 39.5 C95.49,39.5 97.5,41.52 97.5,44 C97.5,46.49 95.49,48.5 93,48.5 C90.52,48.5 88.5,46.49 88.5,44 C88.5,41.52 90.52,39.5 93,39.5c M94 37 C94,37 92,37 92,37 C92,37 92,33 92,33 C92,33 94,33 94,33 C94,33 94,37 94,37c M86 43 C86,43 86,45 86,45 C86,45 82,45 82,45 C82,45 82,43 82,43 C82,43 86,43 86,43c M92 51 C92,51 94,51 94,51 C94,51 94,55 94,55 C94,55 92,55 92,55 C92,55 92,51 92,51c M100 45 C100,45 100,43 100,43 C100,43 104,43 104,43 C104,43 104,45 104,45 C104,45 100,45 100,45c M85.22 37.64 C85.22,37.64 86.64,36.22 86.64,36.22 C86.64,36.22 88.76,38.34 88.76,38.34 C88.76,38.34 87.34,39.76 87.34,39.76 C87.34,39.76 85.22,37.64 85.22,37.64c M86.64 51.78 C86.64,51.78 85.22,50.36 85.22,50.36 C85.22,50.36 87.34,48.24 87.34,48.24 C87.34,48.24 88.76,49.66 88.76,49.66 C88.76,49.66 86.64,51.78 86.64,51.78c M100.78 50.36 C100.78,50.36 99.36,51.78 99.36,51.78 C99.36,51.78 97.24,49.66 97.24,49.66 C97.24,49.66 98.66,48.24 98.66,48.24 C98.66,48.24 100.78,50.36 100.78,50.36c M99.36 36.22 C99.36,36.22 100.78,37.64 100.78,37.64 C100.78,37.64 98.66,39.76 98.66,39.76 C98.66,39.76 97.24,38.34 97.24,38.34 C97.24,38.34 99.36,36.22 99.36,36.22c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 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="350"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#000000"
+ android:valueTo="#ffffff"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 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="350"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M94 37 C94,37 92,37 92,37 C92,37 92,35.44 92,35.44 C92,35.44 94,35.44 94,35.44 C94,35.44 94,37 94,37c M86 43 C86,43 86,45 86,45 C86,45 84.31,45 84.31,45 C84.31,45 84.31,43 84.31,43 C84.31,43 86,43 86,43c M92 51 C92,51 94,51 94,51 C94,51 94,52.69 94,52.69 C94,52.69 92,52.69 92,52.69 C92,52.69 92,51 92,51c M100 45 C100,45 100,43 100,43 C100,43 101.75,43 101.75,43 C101.75,43 101.75,45 101.75,45 C101.75,45 100,45 100,45c "
+ android:valueTo="M94 37 C94,37 92,37 92,37 C92,37 92,33 92,33 C92,33 94,33 94,33 C94,33 94,37 94,37c M86 43 C86,43 86,45 86,45 C86,45 82,45 82,45 C82,45 82,43 82,43 C82,43 86,43 86,43c M92 51 C92,51 94,51 94,51 C94,51 94,55 94,55 C94,55 92,55 92,55 C92,55 92,51 92,51c M100 45 C100,45 100,43 100,43 C100,43 104,43 104,43 C104,43 104,45 104,45 C104,45 100,45 100,45c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 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="350"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#000000"
+ android:valueTo="#ffffff"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 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="350"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M86.07 38.57 C86.07,38.57 87.48,37.16 87.48,37.16 C87.48,37.16 88.76,38.34 88.76,38.34 C88.76,38.34 87.34,39.76 87.34,39.76 C87.34,39.76 86.07,38.57 86.07,38.57c M87.57 50.87 C87.57,50.87 86.16,49.46 86.16,49.46 C86.16,49.46 87.34,48.24 87.34,48.24 C87.34,48.24 88.76,49.66 88.76,49.66 C88.76,49.66 87.57,50.87 87.57,50.87c M99.9 49.43 C99.9,49.43 98.49,50.84 98.49,50.84 C98.49,50.84 97.24,49.66 97.24,49.66 C97.24,49.66 98.66,48.24 98.66,48.24 C98.66,48.24 99.9,49.43 99.9,49.43c M98.52 37.13 C98.52,37.13 99.93,38.54 99.93,38.54 C99.93,38.54 98.66,39.76 98.66,39.76 C98.66,39.76 97.24,38.34 97.24,38.34 C97.24,38.34 98.52,37.13 98.52,37.13c "
+ android:valueTo="M85.22 37.64 C85.22,37.64 86.64,36.22 86.64,36.22 C86.64,36.22 88.76,38.34 88.76,38.34 C88.76,38.34 87.34,39.76 87.34,39.76 C87.34,39.76 85.22,37.64 85.22,37.64c M86.64 51.78 C86.64,51.78 85.22,50.36 85.22,50.36 C85.22,50.36 87.34,48.24 87.34,48.24 C87.34,48.24 88.76,49.66 88.76,49.66 C88.76,49.66 86.64,51.78 86.64,51.78c M100.78 50.36 C100.78,50.36 99.36,51.78 99.36,51.78 C99.36,51.78 97.24,49.66 97.24,49.66 C97.24,49.66 98.66,48.24 98.66,48.24 C98.66,48.24 100.78,50.36 100.78,50.36c M99.36 36.22 C99.36,36.22 100.78,37.64 100.78,37.64 C100.78,37.64 98.66,39.76 98.66,39.76 C98.66,39.76 97.24,38.34 97.24,38.34 C97.24,38.34 99.36,36.22 99.36,36.22c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,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="517"
+ 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_1_G"
+ android:translateX="-81"
+ android:translateY="-32">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:pathData=" M93 40 C95.21,40 97,41.79 97,44 C97,46.21 95.21,48 93,48 C90.79,48 89,46.21 89,44 C89,41.79 90.79,40 93,40c "
+ android:strokeAlpha="1"
+ android:strokeColor="#000000"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-81"
+ android:translateY="-32">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:pathData=" M93 39.5 C93,39.55 93,41.52 93,44 C93,46.49 93,48.58 93,48.5 C90.52,48.5 88.5,46.49 88.5,44 C88.5,41.52 90.52,39.5 93,39.5c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:pathData=" M94 37 C94,37 92,37 92,37 C92,37 92,35.44 92,35.44 C92,35.44 94,35.44 94,35.44 C94,35.44 94,37 94,37c " />
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:pathData=" M86.07 38.57 C86.07,38.57 87.48,37.16 87.48,37.16 C87.48,37.16 88.76,38.34 88.76,38.34 C88.76,38.34 87.34,39.76 87.34,39.76 C87.34,39.76 86.07,38.57 86.07,38.57c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/qs_extra_dim_icon_on.xml b/packages/SystemUI/res/drawable/qs_extra_dim_icon_on.xml
new file mode 100644
index 0000000..5546b6f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_extra_dim_icon_on.xml
@@ -0,0 +1,197 @@
+<?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_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="350"
+ android:propertyName="strokeColor"
+ android:startOffset="0"
+ android:valueFrom="#ffffff"
+ android:valueTo="#000000"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="350"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#ffffff"
+ android:valueTo="#000000"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="350"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M93 39.5 C95.49,39.5 97.5,41.52 97.5,44 C97.5,46.49 95.49,48.5 93,48.5 C90.52,48.5 88.5,46.49 88.5,44 C88.5,41.52 90.52,39.5 93,39.5c M94 37 C94,37 92,37 92,37 C92,37 92,33 92,33 C92,33 94,33 94,33 C94,33 94,37 94,37c M86 43 C86,43 86,45 86,45 C86,45 82,45 82,45 C82,45 82,43 82,43 C82,43 86,43 86,43c M92 51 C92,51 94,51 94,51 C94,51 94,55 94,55 C94,55 92,55 92,55 C92,55 92,51 92,51c M100 45 C100,45 100,43 100,43 C100,43 104,43 104,43 C104,43 104,45 104,45 C104,45 100,45 100,45c M85.22 37.64 C85.22,37.64 86.64,36.22 86.64,36.22 C86.64,36.22 88.76,38.34 88.76,38.34 C88.76,38.34 87.34,39.76 87.34,39.76 C87.34,39.76 85.22,37.64 85.22,37.64c M86.64 51.78 C86.64,51.78 85.22,50.36 85.22,50.36 C85.22,50.36 87.34,48.24 87.34,48.24 C87.34,48.24 88.76,49.66 88.76,49.66 C88.76,49.66 86.64,51.78 86.64,51.78c M100.78 50.36 C100.78,50.36 99.36,51.78 99.36,51.78 C99.36,51.78 97.24,49.66 97.24,49.66 C97.24,49.66 98.66,48.24 98.66,48.24 C98.66,48.24 100.78,50.36 100.78,50.36c M99.36 36.22 C99.36,36.22 100.78,37.64 100.78,37.64 C100.78,37.64 98.66,39.76 98.66,39.76 C98.66,39.76 97.24,38.34 97.24,38.34 C97.24,38.34 99.36,36.22 99.36,36.22c "
+ android:valueTo="M93 39.5 C93,39.55 93,41.52 93,44 C93,46.49 93,48.58 93,48.5 C90.52,48.5 88.5,46.49 88.5,44 C88.5,41.52 90.52,39.5 93,39.5c M94 37 C94,37 92,37 92,37 C92,37 92,35.44 92,35.44 C92,35.44 94,35.44 94,35.44 C94,35.44 94,37 94,37c M86 43 C86,43 86,45 86,45 C86,45 84.31,45 84.31,45 C84.31,45 84.31,43 84.31,43 C84.31,43 86,43 86,43c M92 51 C92,51 94,51 94,51 C94,51 94,52.69 94,52.69 C94,52.69 92,52.69 92,52.69 C92,52.69 92,51 92,51c M100 45 C100,45 100,43 100,43 C100,43 101.75,43 101.75,43 C101.75,43 101.75,45 101.75,45 C101.75,45 100,45 100,45c M86.07 38.57 C86.07,38.57 87.48,37.16 87.48,37.16 C87.48,37.16 88.76,38.34 88.76,38.34 C88.76,38.34 87.34,39.76 87.34,39.76 C87.34,39.76 86.07,38.57 86.07,38.57c M87.57 50.87 C87.57,50.87 86.16,49.46 86.16,49.46 C86.16,49.46 87.34,48.24 87.34,48.24 C87.34,48.24 88.76,49.66 88.76,49.66 C88.76,49.66 87.57,50.87 87.57,50.87c M99.9 49.43 C99.9,49.43 98.49,50.84 98.49,50.84 C98.49,50.84 97.24,49.66 97.24,49.66 C97.24,49.66 98.66,48.24 98.66,48.24 C98.66,48.24 99.9,49.43 99.9,49.43c M98.52 37.13 C98.52,37.13 99.93,38.54 99.93,38.54 C99.93,38.54 98.66,39.76 98.66,39.76 C98.66,39.76 97.24,38.34 97.24,38.34 C97.24,38.34 98.52,37.13 98.52,37.13c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 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="350"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#ffffff"
+ android:valueTo="#000000"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 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="350"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M94 37 C94,37 92,37 92,37 C92,37 92,33 92,33 C92,33 94,33 94,33 C94,33 94,37 94,37c M86 43 C86,43 86,45 86,45 C86,45 82,45 82,45 C82,45 82,43 82,43 C82,43 86,43 86,43c M92 51 C92,51 94,51 94,51 C94,51 94,55 94,55 C94,55 92,55 92,55 C92,55 92,51 92,51c M100 45 C100,45 100,43 100,43 C100,43 104,43 104,43 C104,43 104,45 104,45 C104,45 100,45 100,45c "
+ android:valueTo="M94 37 C94,37 92,37 92,37 C92,37 92,35.44 92,35.44 C92,35.44 94,35.44 94,35.44 C94,35.44 94,37 94,37c M86 43 C86,43 86,45 86,45 C86,45 84.31,45 84.31,45 C84.31,45 84.31,43 84.31,43 C84.31,43 86,43 86,43c M92 51 C92,51 94,51 94,51 C94,51 94,52.69 94,52.69 C94,52.69 92,52.69 92,52.69 C92,52.69 92,51 92,51c M100 45 C100,45 100,43 100,43 C100,43 101.75,43 101.75,43 C101.75,43 101.75,45 101.75,45 C101.75,45 100,45 100,45c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 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="350"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#ffffff"
+ android:valueTo="#000000"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 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="350"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M85.22 37.64 C85.22,37.64 86.64,36.22 86.64,36.22 C86.64,36.22 88.76,38.34 88.76,38.34 C88.76,38.34 87.34,39.76 87.34,39.76 C87.34,39.76 85.22,37.64 85.22,37.64c M86.64 51.78 C86.64,51.78 85.22,50.36 85.22,50.36 C85.22,50.36 87.34,48.24 87.34,48.24 C87.34,48.24 88.76,49.66 88.76,49.66 C88.76,49.66 86.64,51.78 86.64,51.78c M100.78 50.36 C100.78,50.36 99.36,51.78 99.36,51.78 C99.36,51.78 97.24,49.66 97.24,49.66 C97.24,49.66 98.66,48.24 98.66,48.24 C98.66,48.24 100.78,50.36 100.78,50.36c M99.36 36.22 C99.36,36.22 100.78,37.64 100.78,37.64 C100.78,37.64 98.66,39.76 98.66,39.76 C98.66,39.76 97.24,38.34 97.24,38.34 C97.24,38.34 99.36,36.22 99.36,36.22c "
+ android:valueTo="M86.07 38.57 C86.07,38.57 87.48,37.16 87.48,37.16 C87.48,37.16 88.76,38.34 88.76,38.34 C88.76,38.34 87.34,39.76 87.34,39.76 C87.34,39.76 86.07,38.57 86.07,38.57c M87.57 50.87 C87.57,50.87 86.16,49.46 86.16,49.46 C86.16,49.46 87.34,48.24 87.34,48.24 C87.34,48.24 88.76,49.66 88.76,49.66 C88.76,49.66 87.57,50.87 87.57,50.87c M99.9 49.43 C99.9,49.43 98.49,50.84 98.49,50.84 C98.49,50.84 97.24,49.66 97.24,49.66 C97.24,49.66 98.66,48.24 98.66,48.24 C98.66,48.24 99.9,49.43 99.9,49.43c M98.52 37.13 C98.52,37.13 99.93,38.54 99.93,38.54 C99.93,38.54 98.66,39.76 98.66,39.76 C98.66,39.76 97.24,38.34 97.24,38.34 C97.24,38.34 98.52,37.13 98.52,37.13c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,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="517"
+ 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_1_G"
+ android:translateX="-81"
+ android:translateY="-32">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:pathData=" M93 40 C95.21,40 97,41.79 97,44 C97,46.21 95.21,48 93,48 C90.79,48 89,46.21 89,44 C89,41.79 90.79,40 93,40c "
+ android:strokeAlpha="1"
+ android:strokeColor="#ffffff"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-81"
+ android:translateY="-32">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M93 39.5 C95.49,39.5 97.5,41.52 97.5,44 C97.5,46.49 95.49,48.5 93,48.5 C90.52,48.5 88.5,46.49 88.5,44 C88.5,41.52 90.52,39.5 93,39.5c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M94 37 C94,37 92,37 92,37 C92,37 92,33 92,33 C92,33 94,33 94,33 C94,33 94,37 94,37c " />
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#ffffff"
+ android:fillType="nonZero"
+ android:pathData=" M85.22 37.64 C85.22,37.64 86.64,36.22 86.64,36.22 C86.64,36.22 88.76,38.34 88.76,38.34 C88.76,38.34 87.34,39.76 87.34,39.76 C87.34,39.76 85.22,37.64 85.22,37.64c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/qs_flashlight_icon_off.xml b/packages/SystemUI/res/drawable/qs_flashlight_icon_off.xml
new file mode 100644
index 0000000..157e67a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_flashlight_icon_off.xml
@@ -0,0 +1,84 @@
+<?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="417"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M0 2.02 C0.42,2.02 0.77,1.88 1.05,1.59 C1.35,1.29 1.5,0.94 1.5,0.52 C1.5,0.1 1.35,-0.25 1.05,-0.53 C0.77,-0.83 0.42,-0.98 0,-0.98 C-0.42,-0.98 -0.78,-0.83 -1.08,-0.53 C-1.36,-0.25 -1.5,0.1 -1.5,0.52 C-1.5,0.94 -1.36,1.29 -1.08,1.59 C-0.78,1.88 -0.42,2.02 0,2.02c M0 8.62 C-0.42,8.62 -2.78,8.82 -3.07,8.54 C-3.36,8.24 -3.37,-1.87 -3.37,-2.28 C-4.25,-2.69 -4.29,-5.2 -4.01,-5.48 C-3.71,-5.78 -0.42,-5.75 0,-5.75 C0.42,-5.75 4.39,-5.78 4.36,-5.36 C4.22,-2.97 4.47,-3.03 3.34,-1.78 C3.07,-1.48 3.32,8.21 3.02,8.51 C2.74,8.79 0.42,8.62 0,8.62c "
+ android:valueTo="M0 3 C0.42,3 0.77,2.86 1.05,2.58 C1.35,2.28 1.5,1.92 1.5,1.5 C1.5,1.08 1.35,0.73 1.05,0.45 C0.77,0.15 0.42,0 0,0 C-0.42,0 -0.78,0.15 -1.08,0.45 C-1.36,0.73 -1.5,1.08 -1.5,1.5 C-1.5,1.92 -1.36,2.28 -1.08,2.58 C-0.78,2.86 -0.42,3 0,3c M0 8.62 C-0.42,8.62 -2.24,8.83 -2.54,8.55 C-2.83,8.25 -2.86,9.1 -2.86,8.69 C-2.86,8.27 -3.02,8.85 -2.74,8.57 C-2.44,8.26 -0.43,8.31 -0.02,8.31 C0.4,8.31 2.4,8.17 2.68,8.47 C2.98,8.75 2.93,8.33 2.93,8.75 C2.93,9.17 3.32,8.21 3.02,8.51 C2.74,8.79 0.42,8.62 0,8.62c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.1,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="1000"
+ 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_1_G"
+ android:pivotY="24"
+ android:scaleX="0.33332999999999996"
+ android:scaleY="0.33332999999999996"
+ android:translateX="12"
+ android:translateY="-4">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#1f1f1f"
+ android:fillType="nonZero"
+ android:pathData=" M-12 -15 C-12,-15 12,-15 12,-15 C12,-15 12,-13.8 12,-13.8 C12,-13.8 6,-4.8 6,-4.8 C6,-4.8 6,24 6,24 C6,24 -6,24 -6,24 C-6,24 -6,-4.8 -6,-4.8 C-6,-4.8 -12,-13.8 -12,-13.8 C-12,-13.8 -12,-15 -12,-15c M12 -21 C12,-21 -12,-21 -12,-21 C-12,-21 -12,-24 -12,-24 C-12,-24 12,-24 12,-24 C12,-24 12,-21 12,-21c M-12 -3 C-12,-3 -12,30 -12,30 C-12,30 12,30 12,30 C12,30 12,-3 12,-3 C12,-3 18,-12 18,-12 C18,-12 18,-30 18,-30 C18,-30 -18,-30 -18,-30 C-18,-30 -18,-12 -18,-12 C-18,-12 -12,-3 -12,-3c " />
+ </group>
+ <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="#1f1f1f"
+ android:fillType="nonZero"
+ android:pathData=" M0 2.02 C0.42,2.02 0.77,1.88 1.05,1.59 C1.35,1.29 1.5,0.94 1.5,0.52 C1.5,0.1 1.35,-0.25 1.05,-0.53 C0.77,-0.83 0.42,-0.98 0,-0.98 C-0.42,-0.98 -0.78,-0.83 -1.08,-0.53 C-1.36,-0.25 -1.5,0.1 -1.5,0.52 C-1.5,0.94 -1.36,1.29 -1.08,1.59 C-0.78,1.88 -0.42,2.02 0,2.02c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/qs_flashlight_icon_on.xml b/packages/SystemUI/res/drawable/qs_flashlight_icon_on.xml
new file mode 100644
index 0000000..22f5e00
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_flashlight_icon_on.xml
@@ -0,0 +1,84 @@
+<?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="417"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M0 3 C0.42,3 0.77,2.86 1.05,2.58 C1.35,2.28 1.5,1.92 1.5,1.5 C1.5,1.08 1.35,0.73 1.05,0.45 C0.77,0.15 0.42,0 0,0 C-0.42,0 -0.78,0.15 -1.08,0.45 C-1.36,0.73 -1.5,1.08 -1.5,1.5 C-1.5,1.92 -1.36,2.28 -1.08,2.58 C-0.78,2.86 -0.42,3 0,3c M0 8.62 C-0.42,8.62 -2.24,8.83 -2.54,8.55 C-2.83,8.25 -2.86,9.1 -2.86,8.69 C-2.86,8.27 -3.02,8.85 -2.74,8.57 C-2.44,8.26 -0.43,8.31 -0.02,8.31 C0.4,8.31 2.4,8.17 2.68,8.47 C2.98,8.75 2.93,8.33 2.93,8.75 C2.93,9.17 3.32,8.21 3.02,8.51 C2.74,8.79 0.42,8.62 0,8.62c "
+ android:valueTo="M0 2.02 C0.42,2.02 0.77,1.88 1.05,1.59 C1.35,1.29 1.5,0.94 1.5,0.52 C1.5,0.1 1.35,-0.25 1.05,-0.53 C0.77,-0.83 0.42,-0.98 0,-0.98 C-0.42,-0.98 -0.78,-0.83 -1.08,-0.53 C-1.36,-0.25 -1.5,0.1 -1.5,0.52 C-1.5,0.94 -1.36,1.29 -1.08,1.59 C-0.78,1.88 -0.42,2.02 0,2.02c M0 8.62 C-0.42,8.62 -2.78,8.82 -3.07,8.54 C-3.36,8.24 -3.37,-1.87 -3.37,-2.28 C-4.25,-2.69 -4.29,-5.2 -4.01,-5.48 C-3.71,-5.78 -0.42,-5.75 0,-5.75 C0.42,-5.75 4.39,-5.78 4.36,-5.36 C4.22,-2.97 4.47,-3.03 3.34,-1.78 C3.07,-1.48 3.32,8.21 3.02,8.51 C2.74,8.79 0.42,8.62 0,8.62c "
+ 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="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1000"
+ 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_1_G"
+ android:pivotY="24"
+ android:scaleX="0.33332999999999996"
+ android:scaleY="0.33332999999999996"
+ android:translateX="12"
+ android:translateY="-4">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#1f1f1f"
+ android:fillType="nonZero"
+ android:pathData=" M-12 -15 C-12,-15 12,-15 12,-15 C12,-15 12,-13.8 12,-13.8 C12,-13.8 6,-4.8 6,-4.8 C6,-4.8 6,24 6,24 C6,24 -6,24 -6,24 C-6,24 -6,-4.8 -6,-4.8 C-6,-4.8 -12,-13.8 -12,-13.8 C-12,-13.8 -12,-15 -12,-15c M12 -21 C12,-21 -12,-21 -12,-21 C-12,-21 -12,-24 -12,-24 C-12,-24 12,-24 12,-24 C12,-24 12,-21 12,-21c M-12 -3 C-12,-3 -12,30 -12,30 C-12,30 12,30 12,30 C12,30 12,-3 12,-3 C12,-3 18,-12 18,-12 C18,-12 18,-30 18,-30 C18,-30 -18,-30 -18,-30 C-18,-30 -18,-12 -18,-12 C-18,-12 -12,-3 -12,-3c " />
+ </group>
+ <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="#1f1f1f"
+ android:fillType="nonZero"
+ android:pathData=" M0 3 C0.42,3 0.77,2.86 1.05,2.58 C1.35,2.28 1.5,1.92 1.5,1.5 C1.5,1.08 1.35,0.73 1.05,0.45 C0.77,0.15 0.42,0 0,0 C-0.42,0 -0.78,0.15 -1.08,0.45 C-1.36,0.73 -1.5,1.08 -1.5,1.5 C-1.5,1.92 -1.36,2.28 -1.08,2.58 C-0.78,2.86 -0.42,3 0,3c " />
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/qs_nightlight_icon_off.xml b/packages/SystemUI/res/drawable/qs_nightlight_icon_off.xml
new file mode 100644
index 0000000..0769a85
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_nightlight_icon_off.xml
@@ -0,0 +1,94 @@
+<?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_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="283"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="12.125"
+ android:valueTo="12.312"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.1,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="283"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="-45"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.1,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="300"
+ 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_T_1"
+ android:rotation="-45"
+ android:translateX="12.875"
+ android:translateY="12.125">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-2.375">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:pathData=" M3.33 8.62 C2.09,8.68 0.59,8.47 -0.64,7.95 C-1.65,7.53 -2.75,6.9 -3.59,6.09 C-4.38,5.32 -5.19,4.17 -5.61,3.08 C-6.04,1.99 -6.25,0.83 -6.25,-0.39 C-6.25,-1.72 -5.98,-2.85 -5.55,-3.94 C-5.13,-5.02 -4.37,-6 -3.59,-6.78 C-2.63,-7.75 -1.63,-8.28 -0.52,-8.77 C0.48,-9.2 2.04,-9.41 3.15,-9.38 C4.22,-9.35 4.94,-9.16 5.81,-8.79 C5.95,-8.73 6.28,-8.6 6.18,-8.55 C3.44,-6.63 1.83,-3.66 1.83,-0.39 C1.83,2.53 3.47,5.72 6.15,7.86 C6.16,7.9 6.03,7.97 5.91,8.04 C5.12,8.44 4.31,8.56 3.33,8.62c "
+ android:strokeAlpha="1"
+ android:strokeColor="#ffffff"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2" />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/qs_nightlight_icon_on.xml b/packages/SystemUI/res/drawable/qs_nightlight_icon_on.xml
new file mode 100644
index 0000000..5ffe262
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_nightlight_icon_on.xml
@@ -0,0 +1,94 @@
+<?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_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="400"
+ android:propertyName="translateY"
+ android:startOffset="0"
+ android:valueFrom="12.312"
+ android:valueTo="12.125"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.1,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="400"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="-45"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.1,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="417"
+ 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_T_1"
+ android:rotation="0"
+ android:translateX="12.875"
+ android:translateY="12.312">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-2.375">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:pathData=" M3.33 8.62 C2.09,8.68 0.59,8.47 -0.64,7.95 C-1.65,7.53 -2.75,6.9 -3.59,6.09 C-4.38,5.32 -5.19,4.17 -5.61,3.08 C-6.04,1.99 -6.25,0.83 -6.25,-0.39 C-6.25,-1.72 -5.98,-2.85 -5.55,-3.94 C-5.13,-5.02 -4.37,-6 -3.6,-6.78 C-2.63,-7.75 -1.63,-8.28 -0.52,-8.77 C0.48,-9.2 2.04,-9.41 3.14,-9.38 C4.22,-9.35 4.94,-9.16 5.81,-8.79 C5.94,-8.73 6.28,-8.6 6.18,-8.55 C3.44,-6.63 1.83,-3.66 1.83,-0.39 C1.83,2.53 3.47,5.72 6.15,7.86 C6.16,7.9 6.03,7.97 5.91,8.04 C5.13,8.43 4.31,8.56 3.33,8.62c "
+ android:strokeAlpha="1"
+ android:strokeColor="#ffffff"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2" />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/qs_screen_record_icon_off.xml b/packages/SystemUI/res/drawable/qs_screen_record_icon_off.xml
new file mode 100644
index 0000000..b3bdd36
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_screen_record_icon_off.xml
@@ -0,0 +1,218 @@
+<?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_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#000000"
+ android:valueTo="#edf2eb"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M3.5 -2.5 C3.5,-2.5 3.5,2.5 3.5,2.5 C3.5,3.05 3.05,3.5 2.5,3.5 C2.5,3.5 -2.5,3.5 -2.5,3.5 C-3.05,3.5 -3.5,3.05 -3.5,2.5 C-3.5,2.5 -3.5,-2.5 -3.5,-2.5 C-3.5,-3.05 -3.05,-3.5 -2.5,-3.5 C-2.5,-3.5 2.5,-3.5 2.5,-3.5 C3.05,-3.5 3.5,-3.05 3.5,-2.5c "
+ android:valueTo="M3.5 0 C3.5,0.97 3.11,1.84 2.48,2.48 C1.84,3.11 0.97,3.5 0,3.5 C-0.97,3.5 -1.84,3.11 -2.47,2.48 C-3.11,1.84 -3.5,0.97 -3.5,0 C-3.5,-0.97 -3.11,-1.84 -2.47,-2.47 C-1.84,-3.11 -0.97,-3.5 0,-3.5 C0.97,-3.5 1.84,-3.11 2.48,-2.47 C3.11,-1.84 3.5,-0.97 3.5,0c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="90"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#000000"
+ android:valueTo="#edf2eb"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#000000"
+ android:valueTo="#edf2eb"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_2">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#000000"
+ android:valueTo="#edf2eb"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_3">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#000000"
+ android:valueTo="#edf2eb"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,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="1000"
+ 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_1_G"
+ android:rotation="90"
+ android:translateX="12"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:pathData=" M3.5 -2.5 C3.5,-2.5 3.5,2.5 3.5,2.5 C3.5,3.05 3.05,3.5 2.5,3.5 C2.5,3.5 -2.5,3.5 -2.5,3.5 C-3.05,3.5 -3.5,3.05 -3.5,2.5 C-3.5,2.5 -3.5,-2.5 -3.5,-2.5 C-3.5,-3.05 -3.05,-3.5 -2.5,-3.5 C-2.5,-3.5 2.5,-3.5 2.5,-3.5 C3.05,-3.5 3.5,-3.05 3.5,-2.5c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="12"
+ android:translateY="12">
+ <group
+ android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:rotation="0">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:pathData=" M6.6 -4.47 C6.6,-4.47 8.04,-5.91 8.04,-5.91 C9.26,-4.26 9.99,-2.21 10,0.01 C10,2.23 9.26,4.27 8.04,5.93 C8.04,5.93 6.6,4.49 6.6,4.49 C7.47,3.2 7.99,1.66 7.99,0 C7.99,-1.65 7.47,-3.19 6.6,-4.47c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0"
+ android:rotation="0">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_1"
+ android:fillAlpha="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:pathData=" M-8.01 0 C-8.01,1.67 -7.49,3.22 -6.61,4.5 C-6.61,4.5 -8.04,5.93 -8.04,5.93 C-9.27,4.27 -10,2.22 -10,0 C-10,-2.22 -9.27,-4.26 -8.05,-5.92 C-8.05,-5.92 -6.62,-4.49 -6.62,-4.49 C-7.49,-3.21 -8.01,-1.66 -8.01,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_0_P_2_G_0_T_0"
+ android:rotation="0">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_2"
+ android:fillAlpha="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:pathData=" M-0.01 8 C1.66,8 3.2,7.48 4.48,6.61 C4.48,6.61 5.91,8.05 5.91,8.05 C4.25,9.27 2.21,10 -0.01,10 C-2.22,10 -4.26,9.27 -5.92,8.05 C-5.92,8.05 -4.48,6.61 -4.48,6.61 C-3.21,7.48 -1.67,8 -0.01,8c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_0_P_3_G_0_T_0"
+ android:rotation="0">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_3"
+ android:fillAlpha="1"
+ android:fillColor="#000000"
+ android:fillType="nonZero"
+ android:pathData=" M-5.93 -8.04 C-4.27,-9.27 -2.23,-10 -0.01,-10 C2.22,-10 4.26,-9.27 5.94,-8.03 C5.94,-8.03 4.5,-6.59 4.5,-6.59 C3.21,-7.47 1.67,-7.99 0,-7.99 C-1.67,-7.99 -3.21,-7.47 -4.49,-6.6 C-4.49,-6.6 -5.93,-8.04 -5.93,-8.04c " />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/qs_screen_record_icon_on.xml b/packages/SystemUI/res/drawable/qs_screen_record_icon_on.xml
new file mode 100644
index 0000000..facbef5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_screen_record_icon_on.xml
@@ -0,0 +1,286 @@
+<?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_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#edf2eb"
+ android:valueTo="#000000"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M3.5 0 C3.5,0.97 3.11,1.84 2.48,2.48 C1.84,3.11 0.97,3.5 0,3.5 C-0.97,3.5 -1.84,3.11 -2.47,2.48 C-3.11,1.84 -3.5,0.97 -3.5,0 C-3.5,-0.97 -3.11,-1.84 -2.47,-2.47 C-1.84,-3.11 -0.97,-3.5 0,-3.5 C0.97,-3.5 1.84,-3.11 2.48,-2.47 C3.11,-1.84 3.5,-0.97 3.5,0c "
+ android:valueTo="M3.5 -2.5 C3.5,-2.5 3.5,2.5 3.5,2.5 C3.5,3.05 3.05,3.5 2.5,3.5 C2.5,3.5 -2.5,3.5 -2.5,3.5 C-3.05,3.5 -3.5,3.05 -3.5,2.5 C-3.5,2.5 -3.5,-2.5 -3.5,-2.5 C-3.5,-3.05 -3.05,-3.5 -2.5,-3.5 C-2.5,-3.5 2.5,-3.5 2.5,-3.5 C3.05,-3.5 3.5,-3.05 3.5,-2.5c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="90"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#edf2eb"
+ android:valueTo="#000000"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,0.53 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#edf2eb"
+ android:valueTo="#000000"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,0.53 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_2">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#edf2eb"
+ android:valueTo="#000000"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_2_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,0.53 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_3">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="417"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="#edf2eb"
+ android:valueTo="#000000"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_3_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="833"
+ android:propertyName="rotation"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="180"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.7,0 0.2,0.53 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="1000"
+ 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_1_G"
+ android:rotation="0"
+ android:translateX="12"
+ android:translateY="12">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M3.5 0 C3.5,0.97 3.11,1.84 2.48,2.48 C1.84,3.11 0.97,3.5 0,3.5 C-0.97,3.5 -1.84,3.11 -2.47,2.48 C-3.11,1.84 -3.5,0.97 -3.5,0 C-3.5,-0.97 -3.11,-1.84 -2.47,-2.47 C-1.84,-3.11 -0.97,-3.5 0,-3.5 C0.97,-3.5 1.84,-3.11 2.48,-2.47 C3.11,-1.84 3.5,-0.97 3.5,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="12"
+ android:translateY="12">
+ <group
+ android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:rotation="0">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M6.6 -4.47 C6.6,-4.47 8.04,-5.91 8.04,-5.91 C9.26,-4.26 9.99,-2.21 10,0.01 C10,2.23 9.26,4.27 8.04,5.93 C8.04,5.93 6.6,4.49 6.6,4.49 C7.47,3.2 7.99,1.66 7.99,0 C7.99,-1.65 7.47,-3.19 6.6,-4.47c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0"
+ android:rotation="0">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_1"
+ android:fillAlpha="1"
+ android:fillColor="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M-8.01 0 C-8.01,1.67 -7.49,3.22 -6.61,4.5 C-6.61,4.5 -8.04,5.93 -8.04,5.93 C-9.27,4.27 -10,2.22 -10,0 C-10,-2.22 -9.27,-4.26 -8.05,-5.92 C-8.05,-5.92 -6.62,-4.49 -6.62,-4.49 C-7.49,-3.21 -8.01,-1.66 -8.01,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_0_P_2_G_0_T_0"
+ android:rotation="0">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_2"
+ android:fillAlpha="1"
+ android:fillColor="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M-0.01 8 C1.66,8 3.2,7.48 4.48,6.61 C4.48,6.61 5.91,8.05 5.91,8.05 C4.25,9.27 2.21,10 -0.01,10 C-2.22,10 -4.26,9.27 -5.92,8.05 C-5.92,8.05 -4.48,6.61 -4.48,6.61 C-3.21,7.48 -1.67,8 -0.01,8c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_0_P_3_G_0_T_0"
+ android:rotation="0">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_3"
+ android:fillAlpha="1"
+ android:fillColor="#edf2eb"
+ android:fillType="nonZero"
+ android:pathData=" M-5.93 -8.04 C-4.27,-9.27 -2.23,-10 -0.01,-10 C2.22,-10 4.26,-9.27 5.94,-8.03 C5.94,-8.03 4.5,-6.59 4.5,-6.59 C3.21,-7.47 1.67,-7.99 0,-7.99 C-1.67,-7.99 -3.21,-7.47 -4.49,-6.6 C-4.49,-6.6 -5.93,-8.04 -5.93,-8.04c " />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 34e2e83..c2e7445 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -23,6 +23,7 @@
import android.app.compat.ChangeIdStateCache.invalidate
import android.content.Context
import android.graphics.Canvas
+import android.text.Layout
import android.text.TextUtils
import android.text.format.DateFormat
import android.util.AttributeSet
@@ -78,6 +79,8 @@
private var textAnimator: TextAnimator? = null
private var onTextAnimatorInitialized: Runnable? = null
+ @VisibleForTesting var textAnimatorFactory: (Layout, () -> Unit) -> TextAnimator =
+ { layout, invalidateCb -> TextAnimator(layout, invalidateCb) }
@VisibleForTesting var isAnimationEnabled: Boolean = true
@VisibleForTesting var timeOverrideInMillis: Long? = null
@@ -174,7 +177,7 @@
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val animator = textAnimator
if (animator == null) {
- textAnimator = TextAnimator(layout) { invalidate() }
+ textAnimator = textAnimatorFactory(layout, ::invalidate)
onTextAnimatorInitialized?.run()
onTextAnimatorInitialized = null
} else {
@@ -219,9 +222,6 @@
}
fun animateAppearOnLockscreen() {
- if (isAnimationEnabled && textAnimator == null) {
- return
- }
setTextStyle(
weight = dozingWeight,
textSize = -1f,
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 0e1e0cb..b444f4c 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -137,6 +137,10 @@
override fun onThemeChanged() {
updateFun.updateColors()
}
+
+ override fun onDensityOrFontScaleChanged() {
+ clock?.events?.onFontSettingChanged()
+ }
}
private val batteryCallback = object : BatteryStateChangeCallback {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 436b756..8f5cbb7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -54,6 +54,8 @@
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
@@ -127,6 +129,7 @@
private final float mTranslationY;
@ContainerState private int mContainerState = STATE_UNKNOWN;
private final Set<Integer> mFailedModalities = new HashSet<Integer>();
+ private final OnBackInvokedCallback mBackCallback = this::onBackInvoked;
private final @Background DelayableExecutor mBackgroundExecutor;
private int mOrientation;
@@ -362,8 +365,7 @@
return false;
}
if (event.getAction() == KeyEvent.ACTION_UP) {
- sendEarlyUserCanceled();
- animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
+ onBackInvoked();
}
return true;
});
@@ -373,6 +375,11 @@
requestFocus();
}
+ private void onBackInvoked() {
+ sendEarlyUserCanceled();
+ animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
+ }
+
void sendEarlyUserCanceled() {
mConfig.mCallback.onSystemEvent(
BiometricConstants.BIOMETRIC_SYSTEM_EVENT_EARLY_USER_CANCEL, getRequestId());
@@ -520,6 +527,11 @@
.start();
});
}
+ OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
+ if (dispatcher != null) {
+ dispatcher.registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mBackCallback);
+ }
}
private Animator.AnimatorListener getJankListener(View v, String type, long timeout) {
@@ -618,6 +630,10 @@
@Override
public void onDetachedFromWindow() {
+ OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
+ if (dispatcher != null) {
+ findOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mBackCallback);
+ }
super.onDetachedFromWindow();
mWakefulnessLifecycle.removeObserver(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index a3b6cfc..92f37e0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -291,7 +291,6 @@
}
});
mUdfpsController.setAuthControllerUpdateUdfpsLocation(this::updateUdfpsLocation);
- mUdfpsController.setHalControlsIllumination(mUdfpsProps.get(0).halControlsIllumination);
mUdfpsBounds = mUdfpsProps.get(0).getLocation().getRect();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index d7bf261..39291ed 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -264,7 +264,7 @@
acquireInfo: Int
) {
if (biometricSourceType == BiometricSourceType.FINGERPRINT &&
- BiometricFingerprintConstants.shouldTurnOffHbm(acquireInfo) &&
+ BiometricFingerprintConstants.shouldDisableUdfpsDisplayMode(acquireInfo) &&
acquireInfo != BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD) {
// received an 'acquiredBad' message, so immediately retract
mView.retractDwellRipple()
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
index 9281eb8..ad96612 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
@@ -54,13 +54,13 @@
getDrawable().onSensorRectUpdated(bounds);
}
- void onIlluminationStarting() {
- getDrawable().setIlluminationShowing(true);
+ void onDisplayConfiguring() {
+ getDrawable().setDisplayConfigured(true);
getDrawable().invalidateSelf();
}
- void onIlluminationStopped() {
- getDrawable().setIlluminationShowing(false);
+ void onDisplayUnconfigured() {
+ getDrawable().setDisplayConfigured(false);
getDrawable().invalidateSelf();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
index 742c65c..3ad2bef 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
@@ -31,10 +31,10 @@
/**
* Handles:
* 1. registering for listeners when its view is attached and unregistering on view detached
- * 2. pausing udfps when fingerprintManager may still be running but we temporarily want to hide
+ * 2. pausing UDFPS when FingerprintManager may still be running but we temporarily want to hide
* the affordance. this allows us to fade the view in and out nicely (see shouldPauseAuth)
* 3. sending events to its view including:
- * - illumination events
+ * - enabling and disabling of the UDFPS display mode
* - sensor position changes
* - doze time event
*/
@@ -167,19 +167,20 @@
}
/**
- * Udfps has started illuminating and the fingerprint manager is working on authenticating.
+ * The display began transitioning into the UDFPS mode and the fingerprint manager started
+ * authenticating.
*/
- fun onIlluminationStarting() {
- view.onIlluminationStarting()
+ fun onDisplayConfiguring() {
+ view.onDisplayConfiguring()
view.postInvalidate()
}
/**
- * Udfps has stopped illuminating and the fingerprint manager is no longer attempting to
- * authenticate.
+ * The display transitioned away from the UDFPS mode and the fingerprint manager stopped
+ * authenticating.
*/
- fun onIlluminationStopped() {
- view.onIlluminationStopped()
+ fun onDisplayUnconfigured() {
+ view.onDisplayUnconfigured()
view.postInvalidate()
}
@@ -197,4 +198,4 @@
* Called when a view should announce an accessibility event.
*/
open fun doAnnounceForAccessibility(str: String) {}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 7f2680b..36287f5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -86,7 +86,7 @@
/**
* Shows and hides the under-display fingerprint sensor (UDFPS) overlay, handles UDFPS touch events,
- * and coordinates triggering of the high-brightness mode (HBM).
+ * and toggles the UDFPS display mode.
*
* Note that the current architecture is designed so that a single {@link UdfpsController}
* controls/manages all UDFPS sensors. In other words, a single controller is registered with
@@ -123,7 +123,7 @@
@NonNull private final PowerManager mPowerManager;
@NonNull private final AccessibilityManager mAccessibilityManager;
@NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
- @Nullable private final UdfpsHbmProvider mHbmProvider;
+ @Nullable private final UdfpsDisplayModeProvider mUdfpsDisplayMode;
@NonNull private final ConfigurationController mConfigurationController;
@NonNull private final SystemClock mSystemClock;
@NonNull private final UnlockedScreenOffAnimationController
@@ -135,7 +135,6 @@
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
// sensors, this, in addition to a lot of the code here, will be updated.
@VisibleForTesting int mSensorId;
- private boolean mHalControlsIllumination;
@VisibleForTesting @NonNull UdfpsOverlayParams mOverlayParams = new UdfpsOverlayParams();
// TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this.
@Nullable private Runnable mAuthControllerUpdateUdfpsLocation;
@@ -147,10 +146,9 @@
private int mActivePointerId = -1;
// The timestamp of the most recent touch log.
private long mTouchLogTime;
- // Sensor has a capture (good or bad) for this touch. Do not need to illuminate for this
- // particular touch event anymore. In other words, do not illuminate until user lifts and
- // touches the sensor area again.
- // TODO: We should probably try to make touch/illumination things more of a FSM
+ // Sensor has a capture (good or bad) for this touch. No need to enable the UDFPS display mode
+ // anymore for this particular touch event. In other words, do not enable the UDFPS mode until
+ // the user touches the sensor area again.
private boolean mAcquiredReceived;
// The current request from FingerprintService. Null if no current request.
@@ -211,8 +209,8 @@
mKeyguardUpdateMonitor, mDialogManager, mDumpManager,
mLockscreenShadeTransitionController, mConfigurationController,
mSystemClock, mKeyguardStateController,
- mUnlockedScreenOffAnimationController, mHalControlsIllumination,
- mHbmProvider, requestId, reason, callback,
+ mUnlockedScreenOffAnimationController,
+ mUdfpsDisplayMode, requestId, reason, callback,
(view, event, fromUdfpsView) -> onTouch(requestId, event,
fromUdfpsView), mActivityLaunchAnimator)));
}
@@ -236,7 +234,7 @@
int sensorId,
@BiometricFingerprintConstants.FingerprintAcquired int acquiredInfo
) {
- if (BiometricFingerprintConstants.shouldTurnOffHbm(acquiredInfo)) {
+ if (BiometricFingerprintConstants.shouldDisableUdfpsDisplayMode(acquiredInfo)) {
boolean acquiredGood = acquiredInfo == FINGERPRINT_ACQUIRED_GOOD;
mFgExecutor.execute(() -> {
if (mOverlay == null) {
@@ -247,7 +245,7 @@
mAcquiredReceived = true;
final UdfpsView view = mOverlay.getOverlayView();
if (view != null) {
- view.stopIllumination(); // turn off HBM
+ view.unconfigureDisplay();
}
if (acquiredGood) {
mOverlay.onAcquiredGood();
@@ -292,7 +290,7 @@
/**
* Updates the overlay parameters and reconstructs or redraws the overlay, if necessary.
*
- * @param sensorId sensor for which the overlay is getting updated.
+ * @param sensorId sensor for which the overlay is getting updated.
* @param overlayParams See {@link UdfpsOverlayParams}.
*/
public void updateOverlayParams(int sensorId, @NonNull UdfpsOverlayParams overlayParams) {
@@ -321,11 +319,6 @@
mAuthControllerUpdateUdfpsLocation = r;
}
- // TODO(b/229290039): UDFPS controller should manage its properties on its own. Remove this.
- public void setHalControlsIllumination(boolean value) {
- mHalControlsIllumination = value;
- }
-
/**
* Calculate the pointer speed given a velocity tracker and the pointer id.
* This assumes that the velocity tracker has already been passed all relevant motion events.
@@ -369,8 +362,8 @@
}
/**
- * @param x coordinate
- * @param y coordinate
+ * @param x coordinate
+ * @param y coordinate
* @param relativeToUdfpsView true if the coordinates are relative to the udfps view; else,
* calculate from the display dimensions in portrait orientation
*/
@@ -423,7 +416,7 @@
}
final UdfpsView udfpsView = mOverlay.getOverlayView();
- final boolean isIlluminationRequested = udfpsView.isIlluminationRequested();
+ final boolean isDisplayConfigured = udfpsView.isDisplayConfigured();
boolean handled = false;
switch (event.getActionMasked()) {
case MotionEvent.ACTION_OUTSIDE:
@@ -507,7 +500,7 @@
"minor: %.1f, major: %.1f, v: %.1f, exceedsVelocityThreshold: %b",
minor, major, v, exceedsVelocityThreshold);
final long sinceLastLog = mSystemClock.elapsedRealtime() - mTouchLogTime;
- if (!isIlluminationRequested && !mAcquiredReceived
+ if (!isDisplayConfigured && !mAcquiredReceived
&& !exceedsVelocityThreshold) {
final float scale = mOverlayParams.getScaleFactor();
@@ -598,7 +591,7 @@
@NonNull VibratorHelper vibrator,
@NonNull UdfpsHapticsSimulator udfpsHapticsSimulator,
@NonNull UdfpsShell udfpsShell,
- @NonNull Optional<UdfpsHbmProvider> hbmProvider,
+ @NonNull Optional<UdfpsDisplayModeProvider> udfpsDisplayMode,
@NonNull KeyguardStateController keyguardStateController,
@NonNull DisplayManager displayManager,
@Main Handler mainHandler,
@@ -630,7 +623,7 @@
mPowerManager = powerManager;
mAccessibilityManager = accessibilityManager;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
- mHbmProvider = hbmProvider.orElse(null);
+ mUdfpsDisplayMode = udfpsDisplayMode.orElse(null);
screenLifecycle.addObserver(mScreenObserver);
mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
mConfigurationController = configurationController;
@@ -804,15 +797,14 @@
}
/**
- * Cancel updfs scan affordances - ability to hide the HbmSurfaceView (white circle) before
- * user explicitly lifts their finger. Generally, this should be called whenever udfps fails
- * or errors.
+ * Cancel UDFPS affordances - ability to hide the UDFPS overlay before the user explicitly
+ * lifts their finger. Generally, this should be called on errors in the authentication flow.
*
* The sensor that triggers an AOD fingerprint interrupt (see onAodInterrupt) doesn't give
* ACTION_UP/ACTION_CANCEL events, so and AOD interrupt scan needs to be cancelled manually.
* This should be called when authentication either succeeds or fails. Failing to cancel the
- * scan will leave the screen in high brightness mode and will show the HbmSurfaceView until
- * the user lifts their finger.
+ * scan will leave the display in the UDFPS mode until the user lifts their finger. On optical
+ * sensors, this can result in illumination persisting for longer than necessary.
*/
void onCancelUdfps() {
if (mOverlay != null && mOverlay.getOverlayView() != null) {
@@ -874,7 +866,7 @@
Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0);
final UdfpsView view = mOverlay.getOverlayView();
if (view != null) {
- view.startIllumination(() -> {
+ view.configureDisplay(() -> {
if (mAlternateTouchProvider != null) {
mBiometricExecutor.execute(() -> {
mAlternateTouchProvider.onUiReady();
@@ -914,8 +906,8 @@
}
}
mOnFingerDown = false;
- if (view.isIlluminationRequested()) {
- view.stopIllumination();
+ if (view.isDisplayConfigured()) {
+ view.unconfigureDisplay();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index ec72057..1c62f8a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -77,8 +77,7 @@
private val systemClock: SystemClock,
private val keyguardStateController: KeyguardStateController,
private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
- private val halControlsIllumination: Boolean,
- private var hbmProvider: UdfpsHbmProvider,
+ private var udfpsDisplayModeProvider: UdfpsDisplayModeProvider,
val requestId: Long,
@ShowReason val requestReason: Int,
private val controllerCallback: IUdfpsOverlayControllerCallback,
@@ -102,8 +101,8 @@
fitInsetsTypes = 0
gravity = android.view.Gravity.TOP or android.view.Gravity.LEFT
layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
- flags =
- (Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS or WindowManager.LayoutParams.FLAG_SPLIT_TOUCH)
+ flags = (Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS or
+ WindowManager.LayoutParams.FLAG_SPLIT_TOUCH)
privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
// Avoid announcing window title.
accessibilityTitle = " "
@@ -140,8 +139,7 @@
R.layout.udfps_view, null, false
) as UdfpsView).apply {
overlayParams = params
- halControlsIllumination = this@UdfpsControllerOverlay.halControlsIllumination
- setHbmProvider(hbmProvider)
+ setUdfpsDisplayModeProvider(udfpsDisplayModeProvider)
val animation = inflateUdfpsAnimation(this, controller)
if (animation != null) {
animation.init()
@@ -250,8 +248,8 @@
val wasShowing = isShowing
overlayView?.apply {
- if (isIlluminationRequested) {
- stopIllumination()
+ if (isDisplayConfigured) {
+ unconfigureDisplay()
}
windowManager.removeView(this)
setOnTouchListener(null)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDisplayModeProvider.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDisplayModeProvider.java
new file mode 100644
index 0000000..c6957ac
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDisplayModeProvider.java
@@ -0,0 +1,48 @@
+/*
+ * 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.biometrics;
+
+import android.annotation.Nullable;
+
+/**
+ * Interface for toggling the optimal display mode for the under-display fingerprint sensor
+ * (UDFPS). For example, the implementation might change the refresh rate and activate a
+ * high-brightness mode.
+ */
+public interface UdfpsDisplayModeProvider {
+
+ /**
+ * Enables the optimal display mode for UDFPS. The mode will persist until
+ * {@link #disable(Runnable)} is called.
+ *
+ * This call must be made from the UI thread. The callback, if provided, will also be invoked
+ * from the UI thread.
+ *
+ * @param onEnabled A runnable that will be executed once the mode is enabled.
+ */
+ void enable(@Nullable Runnable onEnabled);
+
+ /**
+ * Disables the mode that was enabled by {@link #enable(Runnable)}.
+ *
+ * The call must be made from the UI thread. The callback, if provided, will also be invoked
+ * from the UI thread.
+ *
+ * @param onDisabled A runnable that will be executed once mode is disabled.
+ */
+ void disable(@Nullable Runnable onDisabled);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.kt
index ee112b4..511b4e3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.kt
@@ -51,7 +51,7 @@
invalidateSelf()
}
- var isIlluminationShowing: Boolean = false
+ var isDisplayConfigured: Boolean = false
set(showing) {
if (field == showing) {
return
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
index 1317492..1e35958 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
@@ -197,7 +197,7 @@
@Override
public void draw(@NonNull Canvas canvas) {
- if (isIlluminationShowing()) {
+ if (isDisplayConfigured()) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.kt
index 1afa36b..9f6b6d7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.kt
@@ -23,7 +23,7 @@
*/
class UdfpsFpDrawable(context: Context) : UdfpsDrawable(context) {
override fun draw(canvas: Canvas) {
- if (isIlluminationShowing) {
+ if (isDisplayConfigured) {
return
}
fingerprintDrawable.draw(canvas)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHbmProvider.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHbmProvider.java
deleted file mode 100644
index f26dd5f..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHbmProvider.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.annotation.Nullable;
-
-/**
- * Interface for controlling the high-brightness mode (HBM). UdfpsView can use this callback to
- * enable the HBM while showing the fingerprint illumination, and to disable the HBM after the
- * illumination is no longer necessary.
- */
-public interface UdfpsHbmProvider {
-
- /**
- * UdfpsView will call this to enable the HBM when the fingerprint illumination is needed.
- *
- * This method is a no-op when some type of HBM is already enabled.
- *
- * This method must be called from the UI thread. The callback, if provided, will also be
- * invoked from the UI thread.
- *
- * @param onHbmEnabled A runnable that will be executed once HBM is enabled.
- *
- * TODO(b/231335067): enableHbm with halControlsIllumination=true shouldn't make sense.
- * This only makes sense now because vendor code may rely on the side effects of enableHbm.
- */
- void enableHbm(boolean halControlsIllumination, @Nullable Runnable onHbmEnabled);
-
- /**
- * UdfpsView will call this to disable HBM when illumination is no longer needed.
- *
- * This method will disable HBM if HBM is enabled. Otherwise, if HBM is already disabled,
- * this method is a no-op.
- *
- * The call must be made from the UI thread. The callback, if provided, will also be invoked
- * from the UI thread.
- *
- * @param onHbmDisabled A runnable that will be executed once HBM is disabled.
- */
- void disableHbm(@Nullable Runnable onHbmDisabled);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsIlluminator.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsIlluminator.java
deleted file mode 100644
index f85e936..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsIlluminator.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.annotation.Nullable;
-
-/**
- * Interface that should be implemented by UI's that need to coordinate user touches,
- * views/animations, and modules that start/stop display illumination.
- */
-interface UdfpsIlluminator {
- /**
- * @param hbmProvider Invoked when HBM should be enabled or disabled.
- */
- void setHbmProvider(@Nullable UdfpsHbmProvider hbmProvider);
-
- /**
- * Invoked when illumination should start.
- * @param onIlluminatedRunnable Invoked when the display has been illuminated.
- */
- void startIllumination(@Nullable Runnable onIlluminatedRunnable);
-
- /**
- * Invoked when illumination should end.
- */
- void stopIllumination();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index f28fedb..bc274a0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -101,11 +101,11 @@
}
@Override
- void onIlluminationStarting() {
+ void onDisplayConfiguring() {
}
@Override
- void onIlluminationStopped() {
+ void onDisplayUnconfigured() {
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
index 245c225..a15456d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
@@ -36,12 +36,12 @@
class UdfpsView(
context: Context,
attrs: AttributeSet?
-) : FrameLayout(context, attrs), DozeReceiver, UdfpsIlluminator {
+) : FrameLayout(context, attrs), DozeReceiver {
// sensorRect may be bigger than the sensor. True sensor dimensions are defined in
// overlayParams.sensorBounds
private val sensorRect = RectF()
- private var hbmProvider: UdfpsHbmProvider? = null
+ private var mUdfpsDisplayMode: UdfpsDisplayModeProvider? = null
private val debugTextPaint = Paint().apply {
isAntiAlias = true
color = Color.BLUE
@@ -56,19 +56,12 @@
a.getFloat(R.styleable.UdfpsView_sensorTouchAreaCoefficient, 0f)
}
- private val onIlluminatedDelayMs = context.resources.getInteger(
- com.android.internal.R.integer.config_udfps_illumination_transition_ms
- ).toLong()
-
/** View controller (can be different for enrollment, BiometricPrompt, Keyguard, etc.). */
var animationViewController: UdfpsAnimationViewController<*>? = null
/** Parameters that affect the position and size of the overlay. */
var overlayParams = UdfpsOverlayParams()
- /** Whether the HAL is responsible for enabling and disabling of LHBM. */
- var halControlsIllumination: Boolean = true
-
/** Debug message. */
var debugMessage: String? = null
set(value) {
@@ -76,12 +69,12 @@
postInvalidate()
}
- /** When [startIllumination] has been called but not stopped via [stopIllumination]. */
- var isIlluminationRequested: Boolean = false
+ /** True after the call to [configureDisplay] and before the call to [unconfigureDisplay]. */
+ var isDisplayConfigured: Boolean = false
private set
- override fun setHbmProvider(provider: UdfpsHbmProvider?) {
- hbmProvider = provider
+ fun setUdfpsDisplayModeProvider(udfpsDisplayModeProvider: UdfpsDisplayModeProvider?) {
+ mUdfpsDisplayMode = udfpsDisplayModeProvider
}
// Don't propagate any touch events to the child views.
@@ -124,7 +117,7 @@
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
- if (!isIlluminationRequested) {
+ if (!isDisplayConfigured) {
if (!debugMessage.isNullOrEmpty()) {
canvas.drawText(debugMessage!!, 0f, 160f, debugTextPaint)
}
@@ -147,36 +140,15 @@
!(animationViewController?.shouldPauseAuth() ?: false)
}
- /**
- * Start and run [onIlluminatedRunnable] when the first illumination frame reaches the panel.
- */
- override fun startIllumination(onIlluminatedRunnable: Runnable?) {
- isIlluminationRequested = true
- animationViewController?.onIlluminationStarting()
- doIlluminate(onIlluminatedRunnable)
+ fun configureDisplay(onDisplayConfigured: Runnable) {
+ isDisplayConfigured = true
+ animationViewController?.onDisplayConfiguring()
+ mUdfpsDisplayMode?.enable(onDisplayConfigured)
}
- private fun doIlluminate(onIlluminatedRunnable: Runnable?) {
- // TODO(b/231335067): enableHbm with halControlsIllumination=true shouldn't make sense.
- // This only makes sense now because vendor code may rely on the side effects of enableHbm.
- hbmProvider?.enableHbm(halControlsIllumination) {
- if (onIlluminatedRunnable != null) {
- if (halControlsIllumination) {
- onIlluminatedRunnable.run()
- } else {
- // No framework API can reliably tell when a frame reaches the panel. A timeout
- // is the safest solution.
- postDelayed(onIlluminatedRunnable, onIlluminatedDelayMs)
- }
- } else {
- Log.w(TAG, "doIlluminate | onIlluminatedRunnable is null")
- }
- }
- }
-
- override fun stopIllumination() {
- isIlluminationRequested = false
- animationViewController?.onIlluminationStopped()
- hbmProvider?.disableHbm(null /* onHbmDisabled */)
+ fun unconfigureDisplay() {
+ isDisplayConfigured = false
+ animationViewController?.onDisplayUnconfigured()
+ mUdfpsDisplayMode?.disable(null /* onDisabled */)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index c21e36a..7e499eb 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -119,15 +119,12 @@
*/
public class ClipboardOverlayController {
private static final String TAG = "ClipboardOverlayCtrlr";
- private static final String REMOTE_COPY_ACTION = "android.intent.action.REMOTE_COPY";
/** Constants for screenshot/copy deconflicting */
public static final String SCREENSHOT_ACTION = "com.android.systemui.SCREENSHOT";
public static final String SELF_PERMISSION = "com.android.systemui.permission.SELF";
public static final String COPY_OVERLAY_ACTION = "com.android.systemui.COPY";
- private static final String EXTRA_EDIT_SOURCE_CLIPBOARD = "edit_source_clipboard";
-
private static final int CLIPBOARD_DEFAULT_TIMEOUT_MILLIS = 6000;
private static final int SWIPE_PADDING_DP = 12; // extra padding around views to allow swipe
private static final int FONT_SEARCH_STEP_PX = 4;
@@ -383,7 +380,7 @@
mTextPreview);
accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
}
- Intent remoteCopyIntent = getRemoteCopyIntent(clipData);
+ Intent remoteCopyIntent = IntentCreator.getRemoteCopyIntent(clipData, mContext);
// Only show remote copy if it's available.
PackageManager packageManager = mContext.getPackageManager();
if (packageManager.resolveActivity(
@@ -500,41 +497,19 @@
private void editImage(Uri uri) {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_EDIT_TAPPED);
- String editorPackage = mContext.getString(R.string.config_screenshotEditor);
- Intent editIntent = new Intent(Intent.ACTION_EDIT);
- if (!TextUtils.isEmpty(editorPackage)) {
- editIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
- }
- editIntent.setDataAndType(uri, "image/*");
- editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- editIntent.putExtra(EXTRA_EDIT_SOURCE_CLIPBOARD, true);
- mContext.startActivity(editIntent);
+ mContext.startActivity(IntentCreator.getImageEditIntent(uri, mContext));
animateOut();
}
private void editText() {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_EDIT_TAPPED);
- Intent editIntent = new Intent(mContext, EditTextActivity.class);
- editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- mContext.startActivity(editIntent);
+ mContext.startActivity(IntentCreator.getTextEditorIntent(mContext));
animateOut();
}
private void shareContent(ClipData clip) {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_SHARE_TAPPED);
- Intent shareIntent = new Intent(Intent.ACTION_SEND);
- shareIntent.setDataAndType(
- clip.getItemAt(0).getUri(), clip.getDescription().getMimeType(0));
- shareIntent.putExtra(Intent.EXTRA_TEXT, clip.getItemAt(0).getText().toString());
- if (clip.getItemAt(0).getUri() != null) {
- shareIntent.putExtra(Intent.EXTRA_STREAM, clip.getItemAt(0).getUri());
- shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- }
- Intent chooserIntent = Intent.createChooser(shareIntent, null)
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK)
- .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- mContext.startActivity(chooserIntent);
+ mContext.startActivity(IntentCreator.getShareIntent(clip, mContext));
animateOut();
}
@@ -667,20 +642,6 @@
mContext.getString(R.string.clipboard_edit), null);
}
- private Intent getRemoteCopyIntent(ClipData clipData) {
- Intent nearbyIntent = new Intent(REMOTE_COPY_ACTION);
-
- String remoteCopyPackage = mContext.getString(R.string.config_remoteCopyPackage);
- if (!TextUtils.isEmpty(remoteCopyPackage)) {
- nearbyIntent.setComponent(ComponentName.unflattenFromString(remoteCopyPackage));
- }
-
- nearbyIntent.setClipData(clipData);
- nearbyIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- nearbyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- return nearbyIntent;
- }
-
private void animateIn() {
if (mAccessibilityManager.isEnabled()) {
mDismissButton.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
new file mode 100644
index 0000000..3d5e601
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
@@ -0,0 +1,86 @@
+/*
+ * 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.clipboardoverlay;
+
+import android.content.ClipData;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.text.TextUtils;
+
+import com.android.systemui.R;
+
+class IntentCreator {
+ private static final String EXTRA_EDIT_SOURCE_CLIPBOARD = "edit_source_clipboard";
+ private static final String REMOTE_COPY_ACTION = "android.intent.action.REMOTE_COPY";
+
+ static Intent getTextEditorIntent(Context context) {
+ Intent intent = new Intent(context, EditTextActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ return intent;
+ }
+
+ static Intent getShareIntent(ClipData clipData, Context context) {
+ Intent shareIntent = new Intent(Intent.ACTION_SEND);
+
+ // From the ACTION_SEND docs:
+ // "If using EXTRA_TEXT, the MIME type should be "text/plain"; otherwise it should be the
+ // MIME type of the data in EXTRA_STREAM"
+ if (clipData.getItemAt(0).getUri() != null) {
+ shareIntent.setDataAndType(
+ clipData.getItemAt(0).getUri(), clipData.getDescription().getMimeType(0));
+ shareIntent.putExtra(Intent.EXTRA_STREAM, clipData.getItemAt(0).getUri());
+ shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ } else {
+ shareIntent.putExtra(Intent.EXTRA_TEXT, clipData.getItemAt(0).coerceToText(context));
+ shareIntent.setType("text/plain");
+ }
+ Intent chooserIntent = Intent.createChooser(shareIntent, null)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK)
+ .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ return chooserIntent;
+ }
+
+ static Intent getImageEditIntent(Uri uri, Context context) {
+ String editorPackage = context.getString(R.string.config_screenshotEditor);
+ Intent editIntent = new Intent(Intent.ACTION_EDIT);
+ if (!TextUtils.isEmpty(editorPackage)) {
+ editIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
+ }
+ editIntent.setDataAndType(uri, "image/*");
+ editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ editIntent.putExtra(EXTRA_EDIT_SOURCE_CLIPBOARD, true);
+ return editIntent;
+ }
+
+ static Intent getRemoteCopyIntent(ClipData clipData, Context context) {
+ Intent nearbyIntent = new Intent(REMOTE_COPY_ACTION);
+
+ String remoteCopyPackage = context.getString(R.string.config_remoteCopyPackage);
+ if (!TextUtils.isEmpty(remoteCopyPackage)) {
+ nearbyIntent.setComponent(ComponentName.unflattenFromString(remoteCopyPackage));
+ }
+
+ nearbyIntent.setClipData(clipData);
+ nearbyIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ nearbyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ return nearbyIntent;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/drawable/CircularDrawable.kt b/packages/SystemUI/src/com/android/systemui/common/ui/drawable/CircularDrawable.kt
new file mode 100644
index 0000000..ec71c38
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/drawable/CircularDrawable.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.common.ui.drawable
+
+import android.graphics.Canvas
+import android.graphics.Path
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.DrawableWrapper
+import kotlin.math.min
+
+/** Renders the wrapped [Drawable] as a circle. */
+class CircularDrawable(
+ drawable: Drawable,
+) : DrawableWrapper(drawable) {
+ private val path: Path by lazy { Path() }
+
+ override fun onBoundsChange(bounds: Rect) {
+ super.onBoundsChange(bounds)
+ updateClipPath()
+ }
+
+ override fun draw(canvas: Canvas) {
+ canvas.save()
+ canvas.clipPath(path)
+ drawable?.draw(canvas)
+ canvas.restore()
+ }
+
+ private fun updateClipPath() {
+ path.reset()
+ path.addCircle(
+ bounds.centerX().toFloat(),
+ bounds.centerY().toFloat(),
+ min(bounds.width(), bounds.height()) / 2f,
+ Path.Direction.CW
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 318529b..0469152 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -30,7 +30,7 @@
import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
import com.android.systemui.biometrics.AlternateUdfpsTouchProvider;
-import com.android.systemui.biometrics.UdfpsHbmProvider;
+import com.android.systemui.biometrics.UdfpsDisplayModeProvider;
import com.android.systemui.biometrics.dagger.BiometricsModule;
import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.controls.dagger.ControlsModule;
@@ -197,7 +197,7 @@
abstract CentralSurfaces optionalCentralSurfaces();
@BindsOptionalOf
- abstract UdfpsHbmProvider optionalUdfpsHbmProvider();
+ abstract UdfpsDisplayModeProvider optionalUdfpsDisplayModeProvider();
@BindsOptionalOf
abstract AlternateUdfpsTouchProvider optionalUdfpsTouchProvider();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 2da9232..ddcd053 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -202,7 +202,8 @@
}
}
- // Wrap Keyguard going away animation
+ // Wrap Keyguard going away animation.
+ // Note: Also used for wrapping occlude by Dream animation. It works (with some redundancy).
private static IRemoteTransition wrap(IRemoteAnimationRunner runner) {
return new IRemoteTransition.Stub() {
final ArrayMap<IBinder, IRemoteTransitionFinishedCallback> mFinishCallbacks =
@@ -388,6 +389,27 @@
f = new TransitionFilter();
f.mTypeSet = new int[]{TRANSIT_KEYGUARD_UNOCCLUDE};
mShellTransitions.registerRemote(f, unoccludeTransition);
+
+ Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_OCCLUDE for DREAM");
+ // Register for occluding by Dream
+ f = new TransitionFilter();
+ f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED;
+ f.mRequirements = new TransitionFilter.Requirement[]{
+ new TransitionFilter.Requirement(), new TransitionFilter.Requirement()};
+ // First require at-least one app of type DREAM showing that occludes.
+ f.mRequirements[0].mActivityType = WindowConfiguration.ACTIVITY_TYPE_DREAM;
+ f.mRequirements[0].mMustBeIndependent = false;
+ f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD;
+ f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+ // Then require that we aren't closing any occludes (because this would mean a
+ // regular task->task or activity->activity animation not involving keyguard).
+ f.mRequirements[1].mNot = true;
+ f.mRequirements[1].mMustBeIndependent = false;
+ f.mRequirements[1].mFlags = FLAG_OCCLUDES_KEYGUARD;
+ f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
+ mShellTransitions.registerRemote(f, new RemoteTransition(
+ wrap(mKeyguardViewMediator.getOccludeByDreamAnimationRunner()),
+ getIApplicationThread()));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
index d082655..556560c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
@@ -34,7 +34,7 @@
* is triggered.
*/
interface ColorTransition {
- fun updateColorScheme(scheme: ColorScheme?)
+ fun updateColorScheme(scheme: ColorScheme?): Boolean
}
/**
@@ -64,14 +64,16 @@
applyColor(currentColor)
}
- override fun updateColorScheme(scheme: ColorScheme?) {
+ override fun updateColorScheme(scheme: ColorScheme?): Boolean {
val newTargetColor = if (scheme == null) defaultColor else extractColor(scheme)
if (newTargetColor != targetColor) {
sourceColor = currentColor
targetColor = newTargetColor
valueAnimator.cancel()
valueAnimator.start()
+ return true
}
+ return false
}
init {
@@ -198,8 +200,10 @@
return Utils.getColorAttr(context, id).defaultColor
}
- fun updateColorScheme(colorScheme: ColorScheme?) {
- colorTransitions.forEach { it.updateColorScheme(colorScheme) }
+ fun updateColorScheme(colorScheme: ColorScheme?): Boolean {
+ var anyChanged = false
+ colorTransitions.forEach { anyChanged = it.updateColorScheme(colorScheme) || anyChanged }
colorScheme?.let { mediaViewHolder.gutsViewHolder.colorScheme = colorScheme }
+ return anyChanged
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index b02393b..759795f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -741,10 +741,14 @@
}
mArtworkBoundId = reqId;
+ // Transition Colors to current color scheme
+ boolean colorSchemeChanged = mColorSchemeTransition.updateColorScheme(colorScheme);
+
// Bind the album view to the artwork or a transition drawable
ImageView albumView = mMediaViewHolder.getAlbumView();
albumView.setPadding(0, 0, 0, 0);
- if (updateBackground || (!mIsArtworkBound && isArtworkBound)) {
+ if (updateBackground || colorSchemeChanged
+ || (!mIsArtworkBound && isArtworkBound)) {
if (mPrevArtwork == null) {
albumView.setImageDrawable(artwork);
} else {
@@ -767,9 +771,6 @@
mIsArtworkBound = isArtworkBound;
}
- // Transition Colors to current color scheme
- mColorSchemeTransition.updateColorScheme(colorScheme);
-
// App icon - use notification icon
ImageView appIconView = mMediaViewHolder.getAppIcon();
appIconView.clearColorFilter();
diff --git a/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt b/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
index 88f6f3d..6bc94cd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
@@ -60,6 +60,8 @@
linePaint.strokeWidth = value
}
+ // Enables a transition region where the amplitude
+ // of the wave is reduced linearly across it.
var transitionEnabled = true
set(value) {
field = value
@@ -116,44 +118,40 @@
}
val progress = level / 10_000f
- val totalProgressPx = bounds.width() * progress
- val waveProgressPx = bounds.width() * (
+ val totalWidth = bounds.width().toFloat()
+ val totalProgressPx = totalWidth * progress
+ val waveProgressPx = totalWidth * (
if (!transitionEnabled || progress > matchedWaveEndpoint) progress else
lerp(minWaveEndpoint, matchedWaveEndpoint, lerpInv(0f, matchedWaveEndpoint, progress)))
// Build Wiggly Path
- val waveStart = -phaseOffset
- val waveEnd = waveProgressPx
- val transitionLength = if (transitionEnabled) transitionPeriods * waveLength else 0.01f
+ val waveStart = -phaseOffset - waveLength / 2f
+ val waveEnd = if (transitionEnabled) totalWidth else waveProgressPx
// helper function, computes amplitude for wave segment
val computeAmplitude: (Float, Float) -> Float = { x, sign ->
- sign * heightFraction * lineAmplitude *
- lerpInvSat(waveEnd, waveEnd - transitionLength, x)
+ if (transitionEnabled) {
+ val length = transitionPeriods * waveLength
+ val coeff = lerpInvSat(
+ waveProgressPx + length / 2f,
+ waveProgressPx - length / 2f,
+ x)
+ sign * heightFraction * lineAmplitude * coeff
+ } else {
+ sign * heightFraction * lineAmplitude
+ }
}
- var currentX = waveEnd
- var waveSign = if (phaseOffset < waveLength / 2) 1f else -1f
+ // Reset path object to the start
path.rewind()
+ path.moveTo(waveStart, 0f)
- // Draw flat line from end to wave endpoint
- path.moveTo(bounds.width().toFloat(), 0f)
- path.lineTo(waveEnd, 0f)
-
- // First wave has shortened wavelength
- // approx quarter wave gets us to first wave peak
- // shouldn't be big enough to notice it's not a sin wave
- currentX -= phaseOffset % (waveLength / 2)
- val controlRatio = 0.25f
+ // Build the wave, incrementing by half the wavelength each time
+ var currentX = waveStart
+ var waveSign = 1f
var currentAmp = computeAmplitude(currentX, waveSign)
- path.cubicTo(
- waveEnd, currentAmp * controlRatio,
- lerp(currentX, waveEnd, controlRatio), currentAmp,
- currentX, currentAmp)
-
- // Other waves have full wavelength
- val dist = -1 * waveLength / 2f
- while (currentX > waveStart) {
+ val dist = waveLength / 2f
+ while (currentX < waveEnd) {
waveSign = -waveSign
val nextX = currentX + dist
val midX = currentX + dist / 2
@@ -166,34 +164,35 @@
currentX = nextX
}
- // Draw path; clip to progress position
+ // translate to the start position of the progress bar for all draw commands
+ val clipTop = lineAmplitude + strokeWidth
canvas.save()
canvas.translate(bounds.left.toFloat(), bounds.centerY().toFloat())
- canvas.clipRect(
- 0f,
- -lineAmplitude - strokeWidth,
- totalProgressPx,
- lineAmplitude + strokeWidth)
+
+ // Draw path up to progress position
+ canvas.save()
+ canvas.clipRect(0f, -1f * clipTop, totalProgressPx, clipTop)
canvas.drawPath(path, wavePaint)
canvas.restore()
- // Draw path; clip between progression position & far edge
- canvas.save()
- canvas.translate(bounds.left.toFloat(), bounds.centerY().toFloat())
- canvas.clipRect(
- totalProgressPx,
- -lineAmplitude - strokeWidth,
- bounds.width().toFloat(),
- lineAmplitude + strokeWidth)
- canvas.drawPath(path, linePaint)
- canvas.restore()
+ if (transitionEnabled) {
+ // If there's a smooth transition, we draw the rest of the
+ // path in a different color (using different clip params)
+ canvas.save()
+ canvas.clipRect(totalProgressPx, -1f * clipTop, totalWidth, clipTop)
+ canvas.drawPath(path, linePaint)
+ canvas.restore()
+ } else {
+ // No transition, just draw a flat line to the end of the region.
+ // The discontinuity is hidden by the progress bar thumb shape.
+ canvas.drawLine(totalProgressPx, 0f, totalWidth, 0f, linePaint)
+ }
// Draw round line cap at the beginning of the wave
- val startAmp = cos(abs(waveEnd - phaseOffset) / waveLength * TWO_PI)
- canvas.drawPoint(
- bounds.left.toFloat(),
- bounds.centerY() + startAmp * lineAmplitude * heightFraction,
- wavePaint)
+ val startAmp = cos(abs(waveStart) / waveLength * TWO_PI)
+ canvas.drawPoint(0f, startAmp * lineAmplitude * heightFraction, wavePaint)
+
+ canvas.restore()
}
override fun getOpacity(): Int {
@@ -233,4 +232,4 @@
linePaint.color = ColorUtils.setAlphaComponent(tintColor,
(DISABLED_ALPHA * (alpha / 255f)).toInt())
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index c2a82a7..a31500c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -49,7 +49,6 @@
/** Quick settings tile: Invert colors **/
public class ColorInversionTile extends QSTileImpl<BooleanState> {
- private final Icon mIcon = ResourceIcon.get(drawable.ic_invert_colors);
private final SettingObserver mSetting;
@Inject
@@ -123,7 +122,9 @@
state.value = enabled;
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.label = mContext.getString(R.string.quick_settings_inversion_label);
- state.icon = mIcon;
+ state.icon = ResourceIcon.get(state.value
+ ? drawable.qs_invert_colors_icon_on
+ : drawable.qs_invert_colors_icon_off);
state.expandedAccessibilityClassName = Switch.class.getName();
state.contentDescription = state.label;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 73b0896..a747926 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -43,11 +43,12 @@
import javax.inject.Inject;
-/** Quick settings tile: Control flashlight **/
+/**
+ * Quick settings tile: Control flashlight
+ **/
public class FlashlightTile extends QSTileImpl<BooleanState> implements
FlashlightController.FlashlightListener {
- private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_flashlight);
private final FlashlightController mFlashlightController;
@Inject
@@ -116,19 +117,15 @@
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
- if (state.slash == null) {
- state.slash = new SlashState();
- }
state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
state.secondaryLabel = "";
state.stateDescription = "";
if (!mFlashlightController.isAvailable()) {
- state.icon = mIcon;
- state.slash.isSlashed = true;
state.secondaryLabel = mContext.getString(
R.string.quick_settings_flashlight_camera_in_use);
state.stateDescription = state.secondaryLabel;
state.state = Tile.STATE_UNAVAILABLE;
+ state.icon = ResourceIcon.get(R.drawable.qs_flashlight_icon_off);
return;
}
if (arg instanceof Boolean) {
@@ -140,11 +137,11 @@
} else {
state.value = mFlashlightController.isEnabled();
}
- state.icon = mIcon;
- state.slash.isSlashed = !state.value;
state.contentDescription = mContext.getString(R.string.quick_settings_flashlight_label);
state.expandedAccessibilityClassName = Switch.class.getName();
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ state.icon = ResourceIcon.get(state.value
+ ? R.drawable.qs_flashlight_icon_on : R.drawable.qs_flashlight_icon_off);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index 81813db..0e9f659 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -144,9 +144,10 @@
protected void handleUpdateState(BooleanState state, Object arg) {
state.value = mManager.isNightDisplayActivated();
state.label = mContext.getString(R.string.quick_settings_night_display_label);
- state.icon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_night_display_on);
state.expandedAccessibilityClassName = Switch.class.getName();
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ state.icon = ResourceIcon.get(state.value ? R.drawable.qs_nightlight_icon_on
+ : R.drawable.qs_nightlight_icon_off);
state.secondaryLabel = getSecondaryLabel(state.value);
state.contentDescription = TextUtils.isEmpty(state.secondaryLabel)
? state.label
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
index 6921ad5..1dac339 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
@@ -49,7 +49,6 @@
public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState>
implements ReduceBrightColorsController.Listener{
- private final Icon mIcon = ResourceIcon.get(drawable.ic_reduce_bright_colors);
private final boolean mIsAvailable;
private final ReduceBrightColorsController mReduceBrightColorsController;
private boolean mIsListening;
@@ -111,7 +110,9 @@
state.label = mContext.getString(R.string.reduce_bright_colors_feature_name);
state.expandedAccessibilityClassName = Switch.class.getName();
state.contentDescription = state.label;
- state.icon = mIcon;
+ state.icon = ResourceIcon.get(state.value
+ ? drawable.qs_extra_dim_icon_on
+ : drawable.qs_extra_dim_icon_off);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index 75fb393..f63f044 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -120,7 +120,9 @@
state.value = isRecording || isStarting;
state.state = (isRecording || isStarting) ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.label = mContext.getString(R.string.quick_settings_screen_record_label);
- state.icon = ResourceIcon.get(R.drawable.ic_screenrecord);
+ state.icon = ResourceIcon.get(state.value
+ ? R.drawable.qs_screen_record_icon_on
+ : R.drawable.qs_screen_record_icon_off);
// Show expand icon when clicking will open a dialog
state.forceExpandIcon = state.state == Tile.STATE_INACTIVE;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 6eb54f7..0dfb2f4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -197,6 +197,8 @@
mUiEventLogger.log(InternetDialogEvent.INTERNET_DIALOG_SHOW);
mDialogView = LayoutInflater.from(mContext).inflate(R.layout.internet_connectivity_dialog,
null);
+ mDialogView.setAccessibilityPaneTitle(
+ mContext.getText(R.string.accessibility_desc_quick_settings));
final Window window = getWindow();
window.setContentView(mDialogView);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 4c5c23c..7867147 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -667,9 +667,7 @@
private void setDozing(boolean dozing) {
if (mDozing != dozing) {
mDozing = dozing;
- if (dozing || mBouncer.needsFullscreenBouncer() || mOccluded) {
- reset(dozing /* hideBouncerWhenShowing */);
- }
+ reset(true /* hideBouncerWhenShowing */);
updateStates();
if (!dozing) {
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt
index 83a3d0d..d7ad3ce 100644
--- a/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt
@@ -129,7 +129,10 @@
viewModel.users.collect { users ->
val viewPool =
view.children.filter { it.tag == USER_VIEW_TAG }.toMutableList()
- viewPool.forEach { view.removeView(it) }
+ viewPool.forEach {
+ view.removeView(it)
+ flowWidget.removeView(it)
+ }
users.forEach { userViewModel ->
val userView =
if (viewPool.isNotEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
index 66ce01b..398341d 100644
--- a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
@@ -20,6 +20,7 @@
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.android.systemui.R
+import com.android.systemui.common.ui.drawable.CircularDrawable
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.user.domain.interactor.UserInteractor
import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper
@@ -130,7 +131,7 @@
return UserViewModel(
viewKey = model.id,
name = model.name,
- image = model.image,
+ image = CircularDrawable(model.image),
isSelectionMarkerVisible = model.isSelected,
alpha =
if (model.isSelectable) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index e6a3e74c..3094a8c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -48,6 +48,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@@ -74,6 +75,7 @@
import android.provider.Settings;
import android.provider.Settings.Global;
import android.text.InputFilter;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -1047,7 +1049,13 @@
Events.writeEvent(Events.EVENT_SETTINGS_CLICK);
dismissH(DISMISS_REASON_SETTINGS_CLICKED);
mMediaOutputDialogFactory.dismiss();
- mVolumePanelFactory.create(true /* aboveStatusBar */, null);
+ if (FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_VOLUME_PANEL_IN_SYSTEMUI)) {
+ mVolumePanelFactory.create(true /* aboveStatusBar */, null);
+ } else {
+ mActivityStarter.startActivity(new Intent(Settings.Panel.ACTION_VOLUME),
+ true /* dismissShade */);
+ }
});
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 914d945..25e7dbb 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -119,6 +119,20 @@
}
@Test
+ fun fontChanged_verifyFontSizeUpdated() {
+ clockEventController.clock = clock
+ verify(events).onColorPaletteChanged(any(), any(), any())
+
+ clockEventController.registerListeners()
+
+ val captor = argumentCaptor<ConfigurationController.ConfigurationListener>()
+ verify(configurationController).addCallback(capture(captor))
+ captor.value.onDensityOrFontScaleChanged()
+
+ verify(events).onFontSettingChanged()
+ }
+
+ @Test
fun batteryCallback_keyguardShowingCharging_verifyChargeAnimation() {
clockEventController.clock = clock
clockEventController.registerListeners()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index bf3788e..4a5b23c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -29,6 +29,7 @@
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import android.testing.ViewUtils
+import android.view.KeyEvent
import android.view.View
import android.view.WindowInsets
import android.view.WindowManager
@@ -92,6 +93,21 @@
}
@Test
+ fun testDismissesOnBack() {
+ val container = initializeFingerprintContainer(addToView = true)
+ assertThat(container.parent).isNotNull()
+ val root = container.rootView
+
+ // Simulate back invocation
+ container.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK))
+ container.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK))
+ waitForIdleSync()
+
+ assertThat(container.parent).isNull()
+ assertThat(root.isAttachedToWindow).isFalse()
+ }
+
+ @Test
fun testIgnoresAnimatedInWhenDismissed() {
val container = initializeFingerprintContainer(addToView = false)
container.dismissFromSystemServer()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index cb8358d..5c564e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -17,23 +17,13 @@
package com.android.systemui.biometrics
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
-import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
+import android.hardware.biometrics.BiometricOverlayConstants.*
import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
-import android.view.LayoutInflater
-import android.view.MotionEvent
-import android.view.View
-import android.view.Surface
+import android.view.*
import android.view.Surface.Rotation
-import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
@@ -65,7 +55,6 @@
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
-private const val HAL_CONTROLS_ILLUMINATION = true
private const val REQUEST_ID = 2L
// Dimensions for the current display resolution.
@@ -95,8 +84,9 @@
@Mock private lateinit var configurationController: ConfigurationController
@Mock private lateinit var systemClock: SystemClock
@Mock private lateinit var keyguardStateController: KeyguardStateController
- @Mock private lateinit var unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController
- @Mock private lateinit var hbmProvider: UdfpsHbmProvider
+ @Mock private lateinit var unlockedScreenOffAnimationController:
+ UnlockedScreenOffAnimationController
+ @Mock private lateinit var udfpsDisplayMode: UdfpsDisplayModeProvider
@Mock private lateinit var controllerCallback: IUdfpsOverlayControllerCallback
@Mock private lateinit var udfpsController: UdfpsController
@Mock private lateinit var udfpsView: UdfpsView
@@ -130,8 +120,9 @@
statusBarStateController, panelExpansionStateManager, statusBarKeyguardViewManager,
keyguardUpdateMonitor, dialogManager, dumpManager, transitionController,
configurationController, systemClock, keyguardStateController,
- unlockedScreenOffAnimationController, HAL_CONTROLS_ILLUMINATION, hbmProvider,
- REQUEST_ID, reason, controllerCallback, onTouch, activityLaunchAnimator)
+ unlockedScreenOffAnimationController, udfpsDisplayMode, REQUEST_ID, reason,
+ controllerCallback, onTouch, activityLaunchAnimator
+ )
block()
}
@@ -246,7 +237,7 @@
val didShow = controllerOverlay.show(udfpsController, overlayParams)
verify(windowManager).addView(eq(controllerOverlay.overlayView), any())
- verify(udfpsView).setHbmProvider(eq(hbmProvider))
+ verify(udfpsView).setUdfpsDisplayModeProvider(eq(udfpsDisplayMode))
verify(udfpsView).animationViewController = any()
verify(udfpsView).addView(any())
@@ -351,12 +342,12 @@
}
@Test
- fun stopIlluminatingOnHide() = withReason(REASON_AUTH_BP) {
- whenever(udfpsView.isIlluminationRequested).thenReturn(true)
+ fun unconfigureDisplayOnHide() = withReason(REASON_AUTH_BP) {
+ whenever(udfpsView.isDisplayConfigured).thenReturn(true)
controllerOverlay.show(udfpsController, overlayParams)
controllerOverlay.hide()
- verify(udfpsView).stopIllumination()
+ verify(udfpsView).unconfigureDisplay()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 09dc8e4..08b1c28 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -125,7 +125,7 @@
@Mock
private WindowManager mWindowManager;
@Mock
- private UdfpsHbmProvider mHbmProvider;
+ private UdfpsDisplayModeProvider mDisplayModeProvider;
@Mock
private StatusBarStateController mStatusBarStateController;
@Mock
@@ -193,7 +193,7 @@
private IUdfpsOverlayController mOverlayController;
@Captor private ArgumentCaptor<UdfpsView.OnTouchListener> mTouchListenerCaptor;
@Captor private ArgumentCaptor<View.OnHoverListener> mHoverListenerCaptor;
- @Captor private ArgumentCaptor<Runnable> mOnIlluminatedRunnableCaptor;
+ @Captor private ArgumentCaptor<Runnable> mOnDisplayConfiguredCaptor;
@Captor private ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor;
private ScreenLifecycle.Observer mScreenObserver;
@@ -256,7 +256,7 @@
mVibrator,
mUdfpsHapticsSimulator,
mUdfpsShell,
- Optional.of(mHbmProvider),
+ Optional.of(mDisplayModeProvider),
mKeyguardStateController,
mDisplayManager,
mHandler,
@@ -506,7 +506,7 @@
final float expectedMajor = touchMajor / scaleFactor;
// Configure UdfpsView to accept the ACTION_DOWN event
- when(mUdfpsView.isIlluminationRequested()).thenReturn(false);
+ when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
// Show the overlay.
@@ -584,7 +584,7 @@
@Test
public void fingerDown() throws RemoteException {
// Configure UdfpsView to accept the ACTION_DOWN event
- when(mUdfpsView.isIlluminationRequested()).thenReturn(false);
+ when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
@@ -611,12 +611,12 @@
verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(), anyInt(),
anyFloat(), anyFloat());
verify(mLatencyTracker).onActionStart(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
- // AND illumination begins
- verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
+ // AND display configuration begins
+ verify(mUdfpsView).configureDisplay(mOnDisplayConfiguredCaptor.capture());
verify(mLatencyTracker, never()).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
verify(mKeyguardUpdateMonitor).onUdfpsPointerDown(eq((int) TEST_REQUEST_ID));
- // AND onIlluminatedRunnable notifies FingerprintManager about onUiReady
- mOnIlluminatedRunnableCaptor.getValue().run();
+ // AND onDisplayConfigured notifies FingerprintManager about onUiReady
+ mOnDisplayConfiguredCaptor.getValue().run();
mBiometricsExecutor.runAllReady();
InOrder inOrder = inOrder(mAlternateTouchProvider, mLatencyTracker);
inOrder.verify(mAlternateTouchProvider).onUiReady();
@@ -634,10 +634,10 @@
// WHEN fingerprint is requested because of AOD interrupt
mUdfpsController.onAodInterrupt(0, 0, 2f, 3f);
mFgExecutor.runAllReady();
- // THEN illumination begins
- // AND onIlluminatedRunnable that notifies FingerprintManager is set
- verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
- mOnIlluminatedRunnableCaptor.getValue().run();
+ // THEN display configuration begins
+ // AND onDisplayConfigured notifies FingerprintManager about onUiReady
+ verify(mUdfpsView).configureDisplay(mOnDisplayConfiguredCaptor.capture());
+ mOnDisplayConfiguredCaptor.getValue().run();
mBiometricsExecutor.runAllReady();
verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID),
eq(0), eq(0), eq(3f) /* minor */, eq(2f) /* major */);
@@ -655,11 +655,11 @@
mFgExecutor.runAllReady();
when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
- when(mUdfpsView.isIlluminationRequested()).thenReturn(true);
+ when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
// WHEN it is cancelled
mUdfpsController.onCancelUdfps();
- // THEN the illumination is hidden
- verify(mUdfpsView).stopIllumination();
+ // THEN the display is unconfigured
+ verify(mUdfpsView).unconfigureDisplay();
}
@Test
@@ -672,12 +672,12 @@
when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
mFgExecutor.runAllReady();
- when(mUdfpsView.isIlluminationRequested()).thenReturn(true);
+ when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
// WHEN it times out
mFgExecutor.advanceClockToNext();
mFgExecutor.runAllReady();
- // THEN the illumination is hidden
- verify(mUdfpsView).stopIllumination();
+ // THEN the display is unconfigured
+ verify(mUdfpsView).unconfigureDisplay();
}
@Test
@@ -692,8 +692,8 @@
when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
- // THEN no illumination because screen is off
- verify(mUdfpsView, never()).startIllumination(any());
+ // THEN display doesn't get configured because it's off
+ verify(mUdfpsView, never()).configureDisplay(any());
}
@Test
@@ -709,14 +709,14 @@
when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(false);
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
- // THEN no illumination because screen is off
- verify(mUdfpsView, never()).startIllumination(any());
+ // THEN display doesn't get configured because it's off
+ verify(mUdfpsView, never()).configureDisplay(any());
}
@Test
public void playHapticOnTouchUdfpsArea_a11yTouchExplorationEnabled() throws RemoteException {
// Configure UdfpsView to accept the ACTION_DOWN event
- when(mUdfpsView.isIlluminationRequested()).thenReturn(false);
+ when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
// GIVEN that the overlay is showing and a11y touch exploration enabled
@@ -751,7 +751,7 @@
@Test
public void noHapticOnTouchUdfpsArea_a11yTouchExplorationDisabled() throws RemoteException {
// Configure UdfpsView to accept the ACTION_DOWN event
- when(mUdfpsView.isIlluminationRequested()).thenReturn(false);
+ when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
// GIVEN that the overlay is showing and a11y touch exploration NOT enabled
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
index 0327cfc..b78c063 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
@@ -36,13 +36,12 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.nullable
import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
private const val SENSOR_X = 50
private const val SENSOR_Y = 250
@@ -57,7 +56,7 @@
var rule = MockitoJUnit.rule()
@Mock
- lateinit var hbmProvider: UdfpsHbmProvider
+ lateinit var hbmProvider: UdfpsDisplayModeProvider
@Mock
lateinit var animationViewController: UdfpsAnimationViewController<UdfpsAnimationView>
@@ -66,13 +65,11 @@
@Before
fun setup() {
context.setTheme(R.style.Theme_AppCompat)
- context.orCreateTestableResources.addOverride(
- com.android.internal.R.integer.config_udfps_illumination_transition_ms, 0)
view = LayoutInflater.from(context).inflate(R.layout.udfps_view, null) as UdfpsView
view.animationViewController = animationViewController
val sensorBounds = SensorLocationInternal("", SENSOR_X, SENSOR_Y, SENSOR_RADIUS).rect
view.overlayParams = UdfpsOverlayParams(sensorBounds, 1920, 1080, 1f, Surface.ROTATION_0)
- view.setHbmProvider(hbmProvider)
+ view.setUdfpsDisplayModeProvider(hbmProvider)
ViewUtils.attachView(view)
}
@@ -143,27 +140,27 @@
@Test
fun startAndStopIllumination() {
val onDone: Runnable = mock()
- view.startIllumination(onDone)
+ view.configureDisplay(onDone)
val illuminator = withArgCaptor<Runnable> {
- verify(hbmProvider).enableHbm(anyBoolean(), capture())
+ verify(hbmProvider).enable(capture())
}
- assertThat(view.isIlluminationRequested).isTrue()
- verify(animationViewController).onIlluminationStarting()
- verify(animationViewController, never()).onIlluminationStopped()
+ assertThat(view.isDisplayConfigured).isTrue()
+ verify(animationViewController).onDisplayConfiguring()
+ verify(animationViewController, never()).onDisplayUnconfigured()
verify(onDone, never()).run()
// fake illumination event
illuminator.run()
waitForLooper()
verify(onDone).run()
- verify(hbmProvider, never()).disableHbm(any())
+ verify(hbmProvider, never()).disable(any())
- view.stopIllumination()
- assertThat(view.isIlluminationRequested).isFalse()
- verify(animationViewController).onIlluminationStopped()
- verify(hbmProvider).disableHbm(nullable(Runnable::class.java))
+ view.unconfigureDisplay()
+ assertThat(view.isDisplayConfigured).isFalse()
+ verify(animationViewController).onDisplayUnconfigured()
+ verify(hbmProvider).disable(nullable(Runnable::class.java))
}
private fun waitForLooper() = TestableLooper.get(this).processAllMessages()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
new file mode 100644
index 0000000..08fe7c4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.clipboardoverlay;
+
+import android.content.ClipData;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.net.Uri;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class IntentCreatorTest extends SysuiTestCase {
+ private static final int EXTERNAL_INTENT_FLAGS = Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION;
+
+ @Test
+ public void test_getTextEditorIntent() {
+ Intent intent = IntentCreator.getTextEditorIntent(getContext());
+ assertEquals(new ComponentName(getContext(), EditTextActivity.class),
+ intent.getComponent());
+ assertFlags(intent, Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ }
+
+ @Test
+ public void test_getRemoteCopyIntent() {
+ getContext().getOrCreateTestableResources().addOverride(R.string.config_remoteCopyPackage,
+ "");
+
+ ClipData clipData = ClipData.newPlainText("Test", "Test Item");
+ Intent intent = IntentCreator.getRemoteCopyIntent(clipData, getContext());
+
+ assertEquals(null, intent.getComponent());
+ assertFlags(intent, EXTERNAL_INTENT_FLAGS);
+ assertEquals(clipData, intent.getClipData());
+
+ // Try again with a remote copy component
+ ComponentName fakeComponent = new ComponentName("com.android.remotecopy",
+ "com.android.remotecopy.RemoteCopyActivity");
+ getContext().getOrCreateTestableResources().addOverride(R.string.config_remoteCopyPackage,
+ fakeComponent.flattenToString());
+
+ intent = IntentCreator.getRemoteCopyIntent(clipData, getContext());
+ assertEquals(fakeComponent, intent.getComponent());
+ }
+
+ @Test
+ public void test_getImageEditIntent() {
+ getContext().getOrCreateTestableResources().addOverride(R.string.config_screenshotEditor,
+ "");
+ Uri fakeUri = Uri.parse("content://foo");
+ Intent intent = IntentCreator.getImageEditIntent(fakeUri, getContext());
+
+ assertEquals(Intent.ACTION_EDIT, intent.getAction());
+ assertEquals("image/*", intent.getType());
+ assertEquals(null, intent.getComponent());
+ assertFlags(intent, EXTERNAL_INTENT_FLAGS);
+
+ // try again with an editor component
+ ComponentName fakeComponent = new ComponentName("com.android.remotecopy",
+ "com.android.remotecopy.RemoteCopyActivity");
+ getContext().getOrCreateTestableResources().addOverride(R.string.config_screenshotEditor,
+ fakeComponent.flattenToString());
+ intent = IntentCreator.getImageEditIntent(fakeUri, getContext());
+ assertEquals(fakeComponent, intent.getComponent());
+ }
+
+ @Test
+ public void test_getShareIntent_plaintext() {
+ ClipData clipData = ClipData.newPlainText("Test", "Test Item");
+ Intent intent = IntentCreator.getShareIntent(clipData, getContext());
+
+ assertEquals(Intent.ACTION_CHOOSER, intent.getAction());
+ assertFlags(intent, EXTERNAL_INTENT_FLAGS);
+ Intent target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent.class);
+ assertEquals("Test Item", target.getStringExtra(Intent.EXTRA_TEXT));
+ assertEquals("text/plain", target.getType());
+ }
+
+ @Test
+ public void test_getShareIntent_html() {
+ ClipData clipData = ClipData.newHtmlText("Test", "Some HTML",
+ "<b>Some HTML</b>");
+ Intent intent = IntentCreator.getShareIntent(clipData, getContext());
+
+ assertEquals(Intent.ACTION_CHOOSER, intent.getAction());
+ assertFlags(intent, EXTERNAL_INTENT_FLAGS);
+ Intent target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent.class);
+ assertEquals("Some HTML", target.getStringExtra(Intent.EXTRA_TEXT));
+ assertEquals("text/plain", target.getType());
+ }
+
+ @Test
+ public void test_getShareIntent_image() {
+ Uri uri = Uri.parse("content://something");
+ ClipData clipData = new ClipData("Test", new String[]{"image/png"},
+ new ClipData.Item(uri));
+ Intent intent = IntentCreator.getShareIntent(clipData, getContext());
+
+ assertEquals(Intent.ACTION_CHOOSER, intent.getAction());
+ assertFlags(intent, EXTERNAL_INTENT_FLAGS);
+ Intent target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent.class);
+ assertEquals(uri, target.getData());
+ assertEquals("image/png", target.getType());
+ }
+
+ // Assert that the given flags are set
+ private void assertFlags(Intent intent, int flags) {
+ assertTrue((intent.getFlags() & flags) == flags);
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index bef4695..7de5719 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -591,14 +591,20 @@
@Test
fun bindAlbumView_bitmapInLaterStates_setAfterExecutors() {
- val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
- val canvas = Canvas(bmp)
- canvas.drawColor(Color.RED)
- val albumArt = Icon.createWithBitmap(bmp)
+ val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val redCanvas = Canvas(redBmp)
+ redCanvas.drawColor(Color.RED)
+ val redArt = Icon.createWithBitmap(redBmp)
+
+ val greenBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val greenCanvas = Canvas(greenBmp)
+ greenCanvas.drawColor(Color.GREEN)
+ val greenArt = Icon.createWithBitmap(greenBmp)
val state0 = mediaData.copy(artwork = null)
- val state1 = mediaData.copy(artwork = albumArt)
- val state2 = mediaData.copy(artwork = albumArt)
+ val state1 = mediaData.copy(artwork = redArt)
+ val state2 = mediaData.copy(artwork = redArt)
+ val state3 = mediaData.copy(artwork = greenArt)
player.attachPlayer(viewHolder)
// First binding sets (empty) drawable
@@ -627,6 +633,12 @@
bgExecutor.runAllReady()
mainExecutor.runAllReady()
verify(albumView, times(2)).setImageDrawable(any(Drawable::class.java))
+
+ // Fourth binding to new image runs transition due to color scheme change
+ player.bindPlayer(state3, PACKAGE)
+ bgExecutor.runAllReady()
+ mainExecutor.runAllReady()
+ verify(albumView, times(3)).setImageDrawable(any(Drawable::class.java))
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
index bf682a8..3fd2501 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
@@ -33,12 +33,15 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
+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.QSTileHost;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.settings.SecureSettings;
@@ -54,6 +57,8 @@
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class ColorInversionTileTest extends SysuiTestCase {
+ private static final Integer COLOR_INVERSION_DISABLED = 0;
+ private static final Integer COLOR_INVERSION_ENABLED = 1;
@Mock
private QSTileHost mHost;
@@ -113,4 +118,24 @@
assertThat(IntentCaptor.getValue().getAction()).isEqualTo(
Settings.ACTION_COLOR_INVERSION_SETTINGS);
}
+
+ @Test
+ public void testIcon_whenColorInversionDisabled_isOffState() {
+ QSTile.BooleanState state = new QSTile.BooleanState();
+
+ mTile.handleUpdateState(state, COLOR_INVERSION_DISABLED);
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_invert_colors_icon_off));
+ }
+
+ @Test
+ public void testIcon_whenColorInversionEnabled_isOnState() {
+ QSTile.BooleanState state = new QSTile.BooleanState();
+
+ mTile.handleUpdateState(state, COLOR_INVERSION_ENABLED);
+
+ assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_invert_colors_icon_on));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt
new file mode 100644
index 0000000..d0f851b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt
@@ -0,0 +1,108 @@
+package com.android.systemui.qs.tiles
+
+import android.content.Context
+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.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.QSTileHost
+import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.statusbar.policy.FlashlightController
+import com.google.common.truth.Truth
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class FlashlightTileTest : SysuiTestCase() {
+
+ @Mock private lateinit var mockContext: Context
+
+ @Mock private lateinit var qsLogger: QSLogger
+
+ @Mock private lateinit var qsHost: QSTileHost
+
+ @Mock private lateinit var metricsLogger: MetricsLogger
+
+ @Mock private lateinit var statusBarStateController: StatusBarStateController
+
+ @Mock private lateinit var activityStarter: ActivityStarter
+
+ @Mock private lateinit var flashlightController: FlashlightController
+
+ private val uiEventLogger = UiEventLoggerFake()
+ private val falsingManager = FalsingManagerFake()
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var tile: FlashlightTile
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ testableLooper = TestableLooper.get(this)
+
+ Mockito.`when`(qsHost.context).thenReturn(mockContext)
+ Mockito.`when`(qsHost.uiEventLogger).thenReturn(uiEventLogger)
+
+ tile =
+ FlashlightTile(
+ qsHost,
+ testableLooper.looper,
+ Handler(testableLooper.looper),
+ falsingManager,
+ metricsLogger,
+ statusBarStateController,
+ activityStarter,
+ qsLogger,
+ flashlightController
+ )
+ }
+
+ @Test
+ fun testIcon_whenFlashlightEnabled_isOnState() {
+ Mockito.`when`(flashlightController.isAvailable).thenReturn(true)
+ Mockito.`when`(flashlightController.isEnabled).thenReturn(true)
+ val state = QSTile.BooleanState()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ Truth.assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_flashlight_icon_on))
+ }
+
+ @Test
+ fun testIcon_whenFlashlightDisabled_isOffState() {
+ Mockito.`when`(flashlightController.isAvailable).thenReturn(true)
+ Mockito.`when`(flashlightController.isEnabled).thenReturn(false)
+ val state = QSTile.BooleanState()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ Truth.assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_flashlight_icon_off))
+ }
+
+ @Test
+ fun testIcon_whenFlashlightUnavailable_isOffState() {
+ Mockito.`when`(flashlightController.isAvailable).thenReturn(false)
+ val state = QSTile.BooleanState()
+
+ tile.handleUpdateState(state, /* arg= */ null)
+
+ Truth.assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_flashlight_icon_off))
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt
new file mode 100644
index 0000000..188c3a3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt
@@ -0,0 +1,132 @@
+/*
+ * 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.hardware.display.ColorDisplayManager
+import android.hardware.display.NightDisplayListener
+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.dagger.NightDisplayListenerModule
+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.LocationController
+import com.google.common.truth.Truth
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class NightDisplayTileTest : SysuiTestCase() {
+ @Mock
+ private lateinit var mHost: QSHost
+
+ @Mock
+ private lateinit var mMetricsLogger: MetricsLogger
+
+ @Mock
+ private lateinit var mStatusBarStateController: StatusBarStateController
+
+ @Mock
+ private lateinit var mActivityStarter: ActivityStarter
+
+ @Mock
+ private lateinit var mQsLogger: QSLogger
+
+ @Mock
+ private lateinit var mLocationController: LocationController
+
+ @Mock
+ private lateinit var mColorDisplayManager: ColorDisplayManager
+
+ @Mock
+ private lateinit var mNightDisplayListenerBuilder: NightDisplayListenerModule.Builder
+
+ @Mock
+ private lateinit var mNightDisplayListener: NightDisplayListener
+
+ private lateinit var mTestableLooper: TestableLooper
+ private lateinit var mTile: NightDisplayTile
+
+ private val mUiEventLogger: UiEventLogger = UiEventLoggerFake()
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ mTestableLooper = TestableLooper.get(this)
+ whenever(mHost.context).thenReturn(mContext)
+ whenever(mHost.uiEventLogger).thenReturn(mUiEventLogger)
+ whenever(mHost.userContext).thenReturn(mContext)
+ whenever(mNightDisplayListenerBuilder.setUser(anyInt())).thenReturn(
+ mNightDisplayListenerBuilder
+ )
+ whenever(mNightDisplayListenerBuilder.build()).thenReturn(mNightDisplayListener)
+
+ mTile = NightDisplayTile(
+ mHost,
+ mTestableLooper.looper,
+ Handler(mTestableLooper.looper),
+ FalsingManagerFake(),
+ mMetricsLogger,
+ mStatusBarStateController,
+ mActivityStarter,
+ mQsLogger,
+ mLocationController,
+ mColorDisplayManager,
+ mNightDisplayListenerBuilder
+ )
+ }
+
+ @Test
+ fun testIcon_whenDisabled_showsOffState() {
+ whenever(mColorDisplayManager.isNightDisplayActivated).thenReturn(false)
+ val state = QSTile.BooleanState()
+
+ mTile.handleUpdateState(state, /* arg= */ null)
+
+ Truth.assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_nightlight_icon_off))
+ }
+
+ @Test
+ fun testIcon_whenEnabled_showsOnState() {
+ whenever(mColorDisplayManager.isNightDisplayActivated).thenReturn(true)
+ val state = QSTile.BooleanState()
+
+ mTile.handleUpdateState(state, /* arg= */ null)
+
+ Truth.assertThat(state.icon)
+ .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_nightlight_icon_on))
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
index 9eb688d..8601d6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
@@ -32,13 +32,16 @@
import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R.drawable;
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.QSTileHost;
import com.android.systemui.qs.ReduceBrightColorsController;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.UserTracker;
import org.junit.Before;
@@ -130,4 +133,26 @@
.setReduceBrightColorsActivated(eq(true));
}
+ @Test
+ public void testIcon_whenTileEnabled_isOnState() {
+ when(mReduceBrightColorsController.isReduceBrightColorsActivated()).thenReturn(true);
+ mTile.refreshState();
+ QSTile.BooleanState state = new QSTile.BooleanState();
+
+ mTile.handleUpdateState(state, /* arg= */ null);
+
+ assertEquals(state.icon, QSTileImpl.ResourceIcon.get(drawable.qs_extra_dim_icon_on));
+ }
+
+ @Test
+ public void testIcon_whenTileDisabled_isOffState() {
+ when(mReduceBrightColorsController.isReduceBrightColorsActivated()).thenReturn(false);
+ mTile.refreshState();
+ QSTile.BooleanState state = new QSTile.BooleanState();
+
+ mTile.handleUpdateState(state, /* arg= */ null);
+
+ assertEquals(state.icon, QSTileImpl.ResourceIcon.get(drawable.qs_extra_dim_icon_off));
+ }
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index e6bd396..30debdf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -41,9 +41,11 @@
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.flags.FeatureFlags;
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.QSTileHost;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -229,4 +231,38 @@
assertFalse(mTile.getState().forceExpandIcon);
}
+
+ @Test
+ public void testIcon_whenRecording_isOnState() {
+ when(mController.isStarting()).thenReturn(false);
+ when(mController.isRecording()).thenReturn(true);
+ QSTile.BooleanState state = new QSTile.BooleanState();
+
+ mTile.handleUpdateState(state, /* arg= */ null);
+
+ assertEquals(state.icon, QSTileImpl.ResourceIcon.get(R.drawable.qs_screen_record_icon_on));
+ }
+
+ @Test
+ public void testIcon_whenStarting_isOnState() {
+ when(mController.isStarting()).thenReturn(true);
+ when(mController.isRecording()).thenReturn(false);
+ QSTile.BooleanState state = new QSTile.BooleanState();
+
+ mTile.handleUpdateState(state, /* arg= */ null);
+
+ assertEquals(state.icon, QSTileImpl.ResourceIcon.get(R.drawable.qs_screen_record_icon_on));
+ }
+
+ @Test
+ public void testIcon_whenRecordingOff_isOffState() {
+ when(mController.isStarting()).thenReturn(false);
+ when(mController.isRecording()).thenReturn(false);
+ QSTile.BooleanState state = new QSTile.BooleanState();
+
+ mTile.handleUpdateState(state, /* arg= */ null);
+
+ assertEquals(state.icon, QSTileImpl.ResourceIcon.get(R.drawable.qs_screen_record_icon_off));
+ }
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index d09a5a1..f922475 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -143,6 +143,12 @@
}
@Test
+ public void createInternetDialog_setAccessibilityPaneTitleToQuickSettings() {
+ assertThat(mDialogView.getAccessibilityPaneTitle())
+ .isEqualTo(mContext.getText(R.string.accessibility_desc_quick_settings));
+ }
+
+ @Test
public void hideWifiViews_WifiViewsGone() {
mInternetDialog.hideWifiViews();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
index 6ce9cff..002ef29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
@@ -34,6 +34,7 @@
import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
import android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION
+import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.util.ScreenshotHelper
import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
@@ -65,6 +66,7 @@
private const val TASK_ID = 1
@RunWith(AndroidTestingRunner::class)
+@SmallTest
class TakeScreenshotServiceTest : SysuiTestCase() {
private val application = mock<Application>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
new file mode 100644
index 0000000..eb34561
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.shared.clocks
+
+import android.testing.AndroidTestingRunner
+import android.view.LayoutInflater
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.TextAnimator
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.junit.MockitoJUnit
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class AnimatableClockViewTest : SysuiTestCase() {
+
+ @JvmField @Rule val mockito = MockitoJUnit.rule()
+
+ @Mock private lateinit var mockTextAnimator: TextAnimator
+ private lateinit var clockView: AnimatableClockView
+
+ @Before
+ fun setUp() {
+ val layoutInflater = LayoutInflater.from(context)
+ clockView =
+ layoutInflater.inflate(R.layout.clock_default_small, null) as AnimatableClockView
+ clockView.textAnimatorFactory = { _, _ -> mockTextAnimator }
+ }
+
+ @Test
+ fun validateColorAnimationRunsBeforeMeasure() {
+ clockView.setColors(100, 200)
+ clockView.animateAppearOnLockscreen()
+ clockView.measure(50, 50)
+
+ verify(mockTextAnimator).glyphFilter = null
+ verify(mockTextAnimator).setTextStyle(300, -1.0f, 200, false, 350L, null, 0L, null)
+ verifyNoMoreInteractions(mockTextAnimator)
+ }
+
+ @Test
+ fun validateColorAnimationRunsAfterMeasure() {
+ clockView.setColors(100, 200)
+ clockView.measure(50, 50)
+ clockView.animateAppearOnLockscreen()
+
+ verify(mockTextAnimator, times(2)).glyphFilter = null
+ verify(mockTextAnimator).setTextStyle(100, -1.0f, 200, false, 0L, null, 0L, null)
+ verify(mockTextAnimator).setTextStyle(300, -1.0f, 200, true, 350L, null, 0L, null)
+ verifyNoMoreInteractions(mockTextAnimator)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index e790d85..a4453f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -26,6 +26,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -505,4 +506,21 @@
mBouncerExpansionCallback.onVisibilityChanged(false);
verify(mCentralSurfaces).setBouncerShowingOverDream(false);
}
+
+ @Test
+ public void testSetDozing_Dozing() {
+ clearInvocations(mBouncer);
+ mStatusBarKeyguardViewManager.onDozingChanged(true);
+ // Once when shown and once with dozing changed.
+ verify(mBouncer, times(1)).hide(false);
+ }
+
+ @Test
+ public void testSetDozing_notDozing() {
+ mStatusBarKeyguardViewManager.onDozingChanged(true);
+ clearInvocations(mBouncer);
+ mStatusBarKeyguardViewManager.onDozingChanged(false);
+ // Once when shown and twice with dozing changed.
+ verify(mBouncer, times(1)).hide(false);
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 99c8495..6417db0 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1109,7 +1109,8 @@
final List<AccessibilityServiceInfo> result = new ArrayList<>(serviceCount);
for (int i = 0; i < serviceCount; ++i) {
final AccessibilityServiceConnection service = services.get(i);
- if ((service.mFeedbackType & feedbackType) != 0) {
+ if ((service.mFeedbackType & feedbackType) != 0
+ || feedbackType == AccessibilityServiceInfo.FEEDBACK_ALL_MASK) {
result.add(service.getServiceInfo());
}
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 0fac808..4d55d4e 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -1786,8 +1786,8 @@
* from receiving events from the profile.
*/
public boolean isPermittedForProfile(int userId) {
- if (!mUserProfiles.canProfileUseBoundServices(userId)) {
- return false;
+ if (!mUserProfiles.isProfileUser(userId)) {
+ return true;
}
DevicePolicyManager dpm =
(DevicePolicyManager) mContext.getSystemService(DEVICE_POLICY_SERVICE);
@@ -1862,16 +1862,16 @@
}
}
- public boolean canProfileUseBoundServices(int userId) {
+ public boolean isProfileUser(int userId) {
synchronized (mCurrentProfiles) {
UserInfo user = mCurrentProfiles.get(userId);
if (user == null) {
return false;
}
if (user.isManagedProfile() || user.isCloneProfile()) {
- return false;
+ return true;
}
- return true;
+ return false;
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4e0cc61..f11801f 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1828,7 +1828,7 @@
} else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
mUserProfiles.updateCache(context);
- if (mUserProfiles.canProfileUseBoundServices(userId)) {
+ if (!mUserProfiles.isProfileUser(userId)) {
// reload per-user settings
mSettingsObserver.update(null);
// Refresh managed services
@@ -1842,7 +1842,7 @@
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
if (userId != USER_NULL) {
mUserProfiles.updateCache(context);
- if (mUserProfiles.canProfileUseBoundServices(userId)) {
+ if (!mUserProfiles.isProfileUser(userId)) {
allowDefaultApprovedServices(userId);
}
}
@@ -1860,7 +1860,7 @@
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
mUserProfiles.updateCache(context);
mAssistants.onUserUnlocked(userId);
- if (mUserProfiles.canProfileUseBoundServices(userId)) {
+ if (!mUserProfiles.isProfileUser(userId)) {
mConditionProviders.onUserUnlocked(userId);
mListeners.onUserUnlocked(userId);
mZenModeHelper.onUserUnlocked(userId);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 4c0a017..2dbeee9 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -8042,11 +8042,7 @@
// Horizontal position
int offsetX = 0;
if (parentBounds.width() != screenResolvedBounds.width()) {
- if (screenResolvedBounds.width() >= parentAppBounds.width()) {
- // If resolved bounds overlap with insets, center within app bounds.
- offsetX = getCenterOffset(
- parentAppBounds.width(), screenResolvedBounds.width());
- } else {
+ if (screenResolvedBounds.width() <= parentAppBounds.width()) {
float positionMultiplier =
mLetterboxUiController.getHorizontalPositionMultiplier(
newParentConfiguration);
@@ -8058,11 +8054,7 @@
// Vertical position
int offsetY = 0;
if (parentBounds.height() != screenResolvedBounds.height()) {
- if (screenResolvedBounds.height() >= parentAppBounds.height()) {
- // If resolved bounds overlap with insets, center within app bounds.
- offsetY = getCenterOffset(
- parentAppBounds.height(), screenResolvedBounds.height());
- } else {
+ if (screenResolvedBounds.height() <= parentAppBounds.height()) {
float positionMultiplier =
mLetterboxUiController.getVerticalPositionMultiplier(
newParentConfiguration);
@@ -8080,6 +8072,15 @@
offsetBounds(resolvedConfig, offsetX, offsetY);
}
+ // If the top is aligned with parentAppBounds add the vertical insets back so that the app
+ // content aligns with the status bar
+ if (resolvedConfig.windowConfiguration.getAppBounds().top == parentAppBounds.top) {
+ resolvedConfig.windowConfiguration.getBounds().top = parentBounds.top;
+ if (mSizeCompatBounds != null) {
+ mSizeCompatBounds.top = parentBounds.top;
+ }
+ }
+
// Since bounds has changed, the configuration needs to be computed accordingly.
getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
}
@@ -8457,7 +8458,7 @@
// Above coordinates are in "@" space, now place "*" and "#" to screen space.
final boolean fillContainer = resolvedBounds.equals(containingBounds);
final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
- final int screenPosY = fillContainer ? containerBounds.top : containerAppBounds.top;
+ final int screenPosY = fillContainer ? containerBounds.top : containerAppBounds.top;
if (screenPosX != 0 || screenPosY != 0) {
if (mSizeCompatBounds != null) {
@@ -8803,24 +8804,22 @@
// Also account for the insets (e.g. display cutouts, navigation bar), which will be
// clipped away later in {@link Task#computeConfigResourceOverrides()}, i.e., the out
// bounds are the app bounds restricted by aspect ratio + clippable insets. Otherwise,
- // the app bounds would end up too small.
+ // the app bounds would end up too small. To achieve this we will also add clippable insets
+ // when the corresponding dimension fully fills the parent
+
int right = activityWidth + containingAppBounds.left;
+ int left = containingAppBounds.left;
if (right >= containingAppBounds.right) {
- right += containingBounds.right - containingAppBounds.right;
+ right = containingBounds.right;
+ left = containingBounds.left;
}
int bottom = activityHeight + containingAppBounds.top;
+ int top = containingAppBounds.top;
if (bottom >= containingAppBounds.bottom) {
- bottom += containingBounds.bottom - containingAppBounds.bottom;
+ bottom = containingBounds.bottom;
+ top = containingBounds.top;
}
- outBounds.set(containingBounds.left, containingBounds.top, right, bottom);
-
- // If the bounds are restricted by fixed aspect ratio, then out bounds should be put in the
- // container app bounds. Otherwise the entire container bounds are available.
- if (!outBounds.equals(containingBounds)) {
- // The horizontal position should not cover insets (e.g. display cutout).
- outBounds.left = containingAppBounds.left;
- }
-
+ outBounds.set(left, top, right, bottom);
return true;
}
diff --git a/services/core/jni/gnss/Utils.cpp b/services/core/jni/gnss/Utils.cpp
index 8f32c47..571534f 100644
--- a/services/core/jni/gnss/Utils.cpp
+++ b/services/core/jni/gnss/Utils.cpp
@@ -195,6 +195,8 @@
flags = static_cast<uint32_t>(location.elapsedRealtime.flags);
if (flags & android::hardware::gnss::ElapsedRealtime::HAS_TIMESTAMP_NS) {
SET(ElapsedRealtimeNanos, location.elapsedRealtime.timestampNs);
+ } else {
+ SET(ElapsedRealtimeNanos, android::elapsedRealtimeNano());
}
if (flags & android::hardware::gnss::ElapsedRealtime::HAS_TIME_UNCERTAINTY_NS) {
SET(ElapsedRealtimeUncertaintyNanos,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 49879efe..7986043 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -1704,8 +1704,8 @@
}
@Test
- public void testInfoIsPermittedForProfile_notAllowed() {
- when(mUserProfiles.canProfileUseBoundServices(anyInt())).thenReturn(false);
+ public void testInfoIsPermittedForProfile_notProfile() {
+ when(mUserProfiles.isProfileUser(anyInt())).thenReturn(false);
IInterface service = mock(IInterface.class);
when(service.asBinder()).thenReturn(mock(IBinder.class));
@@ -1714,12 +1714,12 @@
services.registerSystemService(service, null, 10, 1000);
ManagedServices.ManagedServiceInfo info = services.checkServiceTokenLocked(service);
- assertFalse(info.isPermittedForProfile(0));
+ assertTrue(info.isPermittedForProfile(0));
}
@Test
- public void testInfoIsPermittedForProfile_allows() {
- when(mUserProfiles.canProfileUseBoundServices(anyInt())).thenReturn(true);
+ public void testInfoIsPermittedForProfile_profileAndDpmAllows() {
+ when(mUserProfiles.isProfileUser(anyInt())).thenReturn(true);
when(mDpm.isNotificationListenerServicePermitted(anyString(), anyInt())).thenReturn(true);
IInterface service = mock(IInterface.class);
@@ -1734,6 +1734,22 @@
}
@Test
+ public void testInfoIsPermittedForProfile_profileAndDpmDenies() {
+ when(mUserProfiles.isProfileUser(anyInt())).thenReturn(true);
+ when(mDpm.isNotificationListenerServicePermitted(anyString(), anyInt())).thenReturn(false);
+
+ IInterface service = mock(IInterface.class);
+ when(service.asBinder()).thenReturn(mock(IBinder.class));
+ ManagedServices services = new TestManagedServices(getContext(), mLock, mUserProfiles,
+ mIpm, APPROVAL_BY_PACKAGE);
+ services.registerSystemService(service, null, 10, 1000);
+ ManagedServices.ManagedServiceInfo info = services.checkServiceTokenLocked(service);
+ info.component = new ComponentName("a","b");
+
+ assertFalse(info.isPermittedForProfile(0));
+ }
+
+ @Test
public void testUserProfiles_canProfileUseBoundServices_managedProfile() {
List<UserInfo> users = new ArrayList<>();
UserInfo profile = new UserInfo(ActivityManager.getCurrentUser(), "current", 0);
@@ -1750,9 +1766,9 @@
ManagedServices.UserProfiles profiles = new ManagedServices.UserProfiles();
profiles.updateCache(mContext);
- assertTrue(profiles.canProfileUseBoundServices(ActivityManager.getCurrentUser()));
- assertFalse(profiles.canProfileUseBoundServices(12));
- assertFalse(profiles.canProfileUseBoundServices(13));
+ assertFalse(profiles.isProfileUser(ActivityManager.getCurrentUser()));
+ assertTrue(profiles.isProfileUser(12));
+ assertTrue(profiles.isProfileUser(13));
}
private void resetComponentsAndPackages() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 60d3f10..181e81d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -210,10 +210,8 @@
assertFitted();
// After the orientation of activity is changed, the display is rotated, the aspect
- // ratio should be the same (bounds=[100, 0 - 800, 583], appBounds=[100, 0 - 800, 583]).
+ // ratio should be the same (bounds=[0, 0 - 800, 583], appBounds=[100, 0 - 800, 583]).
assertEquals(appBounds.width(), appBounds.height() * aspectRatio, 0.5f /* delta */);
- // The notch is no longer on top.
- assertEquals(appBounds, mActivity.getBounds());
// Activity max bounds are sandboxed.
assertActivityMaxBoundsSandboxed();
@@ -467,8 +465,6 @@
assertEquals(ROTATION_270, mTask.getWindowConfiguration().getRotation());
assertEquals(origBounds.width(), currentBounds.width());
- // The notch is on horizontal side, so current height changes from 1460 to 1400.
- assertEquals(origBounds.height() - notchHeight, currentBounds.height());
// Make sure the app size is the same
assertEquals(origAppBounds.width(), appBounds.width());
assertEquals(origAppBounds.height(), appBounds.height());
@@ -2271,7 +2267,7 @@
prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED);
// Bounds are letterboxed to respect the provided max aspect ratio.
- assertEquals(mActivity.getBounds(), new Rect(0, 850, 1000, 1950));
+ assertEquals(mActivity.getBounds(), new Rect(0, 0, 1000, 1100));
// Move activity to split screen which has landscape size.
mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents */ false, "test");
@@ -2338,6 +2334,8 @@
@Test
public void testLetterboxDetailsForStatusBar_letterboxNotOverlappingStatusBar() {
+ // Align to center so that we don't overlap with the status bar
+ mAtm.mWindowManager.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f);
final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2800)
.setNotch(100)
.build();
@@ -2354,7 +2352,7 @@
mActivity.mRootWindowContainer.performSurfacePlacement();
Rect mBounds = new Rect(mActivity.getWindowConfiguration().getBounds());
- assertEquals(mBounds, new Rect(0, 750, 1000, 1950));
+ assertEquals(mBounds, new Rect(0, 900, 1000, 2000));
DisplayPolicy displayPolicy = mActivity.getDisplayContent().getDisplayPolicy();
LetterboxDetails[] expectedLetterboxDetails = {new LetterboxDetails(
@@ -2454,7 +2452,7 @@
// At launch.
/* fixedOrientationLetterbox */ new Rect(0, 0, 700, 1400),
// After 90 degree rotation.
- /* sizeCompatUnscaled */ new Rect(0, 700, 700, 2100),
+ /* sizeCompatUnscaled */ new Rect(0, 0, 700, 1400),
// After the display is resized to (700, 1400).
/* sizeCompatScaled */ new Rect(0, 0, 350, 700));
}
@@ -2467,7 +2465,7 @@
// At launch.
/* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400),
// After 90 degree rotation.
- /* sizeCompatUnscaled */ new Rect(350, 700, 1050, 2100),
+ /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400),
// After the display is resized to (700, 1400).
/* sizeCompatScaled */ new Rect(525, 0, 875, 700));
}
@@ -2482,7 +2480,7 @@
// At launch.
/* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400),
// After 90 degree rotation.
- /* sizeCompatUnscaled */ new Rect(350, 700, 1050, 2100),
+ /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400),
// After the display is resized to (700, 1400).
/* sizeCompatScaled */ new Rect(525, 0, 875, 700));
@@ -2492,7 +2490,7 @@
// At launch.
/* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400),
// After 90 degree rotation.
- /* sizeCompatUnscaled */ new Rect(350, 700, 1050, 2100),
+ /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400),
// After the display is resized to (700, 1400).
/* sizeCompatScaled */ new Rect(525, 0, 875, 700));
}
@@ -2505,7 +2503,7 @@
// At launch.
/* fixedOrientationLetterbox */ new Rect(2100, 0, 2800, 1400),
// After 90 degree rotation.
- /* sizeCompatUnscaled */ new Rect(700, 700, 1400, 2100),
+ /* sizeCompatUnscaled */ new Rect(700, 0, 1400, 1400),
// After the display is resized to (700, 1400).
/* sizeCompatScaled */ new Rect(1050, 0, 1400, 700));
}
@@ -2534,6 +2532,64 @@
}
@Test
+ public void testApplyAspectRatio_activityAlignWithParentAppVertical() {
+ // The display's app bounds will be (0, 100, 1000, 2350)
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500)
+ .setCanRotate(false)
+ .setCutout(0, 100, 0, 150)
+ .build();
+
+ setUpApp(display);
+ prepareUnresizable(mActivity, 2.1f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
+ // The activity height is 2100 and the display's app bounds height is 2250, so the activity
+ // can be aligned inside parentAppBounds
+ assertEquals(mActivity.getBounds(), new Rect(0, 0, 1000, 2200));
+ }
+ @Test
+ public void testApplyAspectRatio_activityCannotAlignWithParentAppVertical() {
+ // The display's app bounds will be (0, 100, 1000, 2150)
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2300)
+ .setCanRotate(false)
+ .setCutout(0, 100, 0, 150)
+ .build();
+
+ setUpApp(display);
+ prepareUnresizable(mActivity, 2.1f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
+ // The activity height is 2100 and the display's app bounds height is 2050, so the activity
+ // cannot be aligned inside parentAppBounds and it will fill the parentBounds of the display
+ assertEquals(mActivity.getBounds(), display.getBounds());
+ }
+
+ @Test
+ public void testApplyAspectRatio_activityAlignWithParentAppHorizontal() {
+ // The display's app bounds will be (100, 0, 2350, 1000)
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, 2500, 1000)
+ .setCanRotate(false)
+ .setCutout(100, 0, 150, 0)
+ .build();
+
+ setUpApp(display);
+ prepareUnresizable(mActivity, 2.1f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
+ // The activity width is 2100 and the display's app bounds width is 2250, so the activity
+ // can be aligned inside parentAppBounds
+ assertEquals(mActivity.getBounds(), new Rect(175, 0, 2275, 1000));
+ }
+ @Test
+ public void testApplyAspectRatio_activityCannotAlignWithParentAppHorizontal() {
+ // The display's app bounds will be (100, 0, 2150, 1000)
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, 2300, 1000)
+ .setCanRotate(false)
+ .setCutout(100, 0, 150, 0)
+ .build();
+
+ setUpApp(display);
+ prepareUnresizable(mActivity, 2.1f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
+ // The activity width is 2100 and the display's app bounds width is 2050, so the activity
+ // cannot be aligned inside parentAppBounds and it will fill the parentBounds of the display
+ assertEquals(mActivity.getBounds(), display.getBounds());
+ }
+
+ @Test
public void testUpdateResolvedBoundsHorizontalPosition_activityFillParentWidth() {
// When activity width equals parent width, multiplier shouldn't have any effect.
assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity(
@@ -2608,6 +2664,25 @@
/* sizeCompatScaled */ new Rect(0, 1050, 700, 1400));
}
+ @Test
+ public void testUpdateResolvedBoundsPosition_alignToTop() {
+ final int notchHeight = 100;
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2800)
+ .setNotch(notchHeight)
+ .build();
+ setUpApp(display);
+
+ // Prepare unresizable activity with max aspect ratio
+ prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED);
+
+ Rect mBounds = new Rect(mActivity.getWindowConfiguration().getBounds());
+ Rect appBounds = new Rect(mActivity.getWindowConfiguration().getAppBounds());
+ // The insets should be cut for aspect ratio and then added back because the appBounds
+ // are aligned to the top of the parentAppBounds
+ assertEquals(mBounds, new Rect(0, 0, 1000, 1200));
+ assertEquals(appBounds, new Rect(0, notchHeight, 1000, 1200));
+ }
+
private void assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
float letterboxVerticalPositionMultiplier, Rect fixedOrientationLetterbox,
Rect sizeCompatUnscaled, Rect sizeCompatScaled) {
@@ -2955,7 +3030,7 @@
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
assertTrue(mActivity.inSizeCompatMode());
// Activity is in size compat mode but not scaled.
- assertEquals(new Rect(0, 1050, 1400, 1750), mActivity.getBounds());
+ assertEquals(new Rect(0, 0, 1400, 700), mActivity.getBounds());
}
private void assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity(
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index aa3ca18..bf1d1fa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -143,11 +143,24 @@
mInfo.ownerUid = ownerUid;
return this;
}
- Builder setNotch(int height) {
+ Builder setCutout(int left, int top, int right, int bottom) {
+ final int cutoutFillerSize = 80;
+ Rect boundLeft = left != 0 ? new Rect(0, 0, left, cutoutFillerSize) : null;
+ Rect boundTop = top != 0 ? new Rect(0, 0, cutoutFillerSize, top) : null;
+ Rect boundRight = right != 0 ? new Rect(mInfo.logicalWidth - right, 0,
+ mInfo.logicalWidth, cutoutFillerSize) : null;
+ Rect boundBottom = bottom != 0
+ ? new Rect(0, mInfo.logicalHeight - bottom, cutoutFillerSize,
+ mInfo.logicalHeight) : null;
+
mInfo.displayCutout = new DisplayCutout(
- Insets.of(0, height, 0, 0), null, new Rect(20, 0, 80, height), null, null);
+ Insets.of(left, top, right, bottom),
+ boundLeft, boundTop, boundRight, boundBottom);
return this;
}
+ Builder setNotch(int height) {
+ return setCutout(0, height, 0, 0);
+ }
Builder setStatusBarHeight(int height) {
mStatusBarHeight = height;
return this;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index b6373b4..ef532f5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -238,7 +238,7 @@
// Ensure letterbox vertical position multiplier is not overridden on any device target.
// {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier},
// may be set on some device form factors.
- mAtm.mWindowManager.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f);
+ mAtm.mWindowManager.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.0f);
// Ensure letterbox horizontal reachability treatment isn't overridden on any device target.
// {@link com.android.internal.R.bool.config_letterboxIsHorizontalReachabilityEnabled},
// may be set on some device form factors.
diff --git a/telephony/java/android/telephony/AnomalyReporter.java b/telephony/java/android/telephony/AnomalyReporter.java
index e7d95e4..58974ee 100644
--- a/telephony/java/android/telephony/AnomalyReporter.java
+++ b/telephony/java/android/telephony/AnomalyReporter.java
@@ -27,6 +27,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.ParcelUuid;
+import android.provider.DeviceConfig;
import com.android.internal.telephony.TelephonyStatsLog;
import com.android.internal.util.IndentingPrintWriter;
@@ -57,6 +58,9 @@
public final class AnomalyReporter {
private static final String TAG = "AnomalyReporter";
+ private static final String KEY_IS_TELEPHONY_ANOMALY_REPORT_ENABLED =
+ "is_telephony_anomaly_report_enabled";
+
private static Context sContext = null;
private static Map<UUID, Integer> sEvents = new ConcurrentHashMap<>();
@@ -101,6 +105,12 @@
* @param carrierId the carrier of the id associated with this event.
*/
public static void reportAnomaly(@NonNull UUID eventId, String description, int carrierId) {
+ // Don't report if the server-side flag isn't loaded, as it implies other anomaly report
+ // related config hasn't loaded.
+ boolean isAnomalyReportEnabledFromServer = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_TELEPHONY, KEY_IS_TELEPHONY_ANOMALY_REPORT_ENABLED, false);
+ if (!isAnomalyReportEnabledFromServer) return;
+
if (sContext == null) {
Rlog.w(TAG, "AnomalyReporter not yet initialized, dropping event=" + eventId);
return;
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index d07d809..7740845 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -3426,10 +3426,20 @@
* Get subscriptionInfo list of subscriptions that are in the same group of given subId.
* See {@link #createSubscriptionGroup(List)} for more details.
*
- * Caller will either have {@link android.Manifest.permission#READ_PHONE_STATE}
- * permission or had carrier privilege permission on the subscription.
+ * Caller must have {@link android.Manifest.permission#READ_PHONE_STATE}
+ * or carrier privilege permission on the subscription.
* {@link TelephonyManager#hasCarrierPrivileges()}
*
+ * <p>Starting with API level 33, this method will return an empty List if the caller does
+ * not have access to device identifiers.
+ * This method can be invoked if one of the following requirements is met:
+ * <ul>
+ * <li>If the app has carrier privilege permission.
+ * {@link TelephonyManager#hasCarrierPrivileges()}
+ * <li>If the app has {@link android.Manifest.permission#READ_PHONE_STATE} permission and
+ * access to device identifiers.
+ * </ul>
+ *
* @throws IllegalStateException if Telephony service is in bad state.
* @throws SecurityException if the caller doesn't meet the requirements
* outlined above.