summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt1
-rw-r--r--core/java/android/content/pm/PackageManager.java4
-rw-r--r--core/java/android/os/CombinedMessageQueue/MessageQueue.java11
-rw-r--r--core/java/android/view/NotificationHeaderView.java10
-rw-r--r--core/java/android/view/View.java17
-rw-r--r--core/java/android/view/ViewRootImpl.java13
-rw-r--r--core/java/android/view/ViewRootRectTracker.java21
-rw-r--r--core/java/android/window/flags/lse_desktop_experience.aconfig10
-rw-r--r--core/java/android/window/flags/windowing_frontend.aconfig11
-rw-r--r--core/java/com/android/internal/os/LongArrayMultiStateCounter.java4
-rw-r--r--core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java12
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java4
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogCommandHandler.java4
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogConfigurationService.java6
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java27
-rw-r--r--core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp8
-rw-r--r--core/proto/OWNERS1
-rw-r--r--core/res/res/drawable/progress_ring_watch.xml24
-rw-r--r--core/res/res/values/attrs.xml8
-rw-r--r--core/res/res/values/dimens_watch.xml2
-rw-r--r--core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java70
-rw-r--r--graphics/java/android/framework_graphics.aconfig8
-rw-r--r--graphics/java/android/graphics/drawable/GradientDrawable.java121
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java1
-rw-r--r--packages/SettingsLib/AndroidManifest.xml7
-rw-r--r--packages/SettingsLib/IllustrationPreference/AndroidManifest.xml2
-rw-r--r--packages/SettingsLib/IllustrationPreference/res/values/strings.xml27
-rw-r--r--packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java93
-rw-r--r--packages/SettingsLib/res/layout/activity_create_new_user.xml22
-rw-r--r--packages/SettingsLib/res/values/styles.xml9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java145
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java18
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/NewUserData.java6
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java114
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java4
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java6
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java89
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt27
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt9
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java32
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModelTest.kt54
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorTest.kt88
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt139
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java125
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractor.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt106
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt92
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt4
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java5
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java18
-rw-r--r--services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java3
-rw-r--r--services/core/java/com/android/server/display/feature/DisplayManagerFlags.java13
-rw-r--r--services/core/java/com/android/server/display/feature/display_flags.aconfig11
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java3
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS1
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java44
-rw-r--r--services/core/java/com/android/server/power/stats/processor/BinaryStatePowerStatsProcessor.java13
-rw-r--r--services/core/java/com/android/server/power/stats/processor/BluetoothPowerStatsProcessor.java6
-rw-r--r--services/core/java/com/android/server/power/stats/processor/CpuPowerStatsProcessor.java6
-rw-r--r--services/core/java/com/android/server/power/stats/processor/CustomEnergyConsumerPowerStatsProcessor.java9
-rw-r--r--services/core/java/com/android/server/power/stats/processor/MobileRadioPowerStatsProcessor.java6
-rw-r--r--services/core/java/com/android/server/power/stats/processor/MultiStateStats.java5
-rw-r--r--services/core/java/com/android/server/power/stats/processor/PowerComponentAggregatedPowerStats.java8
-rw-r--r--services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java8
-rw-r--r--services/core/java/com/android/server/power/stats/processor/WifiPowerStatsProcessor.java6
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java3
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java107
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java2
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java13
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java13
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java5
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/processor/MultiStateStatsTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java18
-rw-r--r--tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java13
-rw-r--r--tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java9
-rw-r--r--tests/testables/src/android/testing/TestableLooper.java2
89 files changed, 1452 insertions, 757 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index f5dcf2de4c51..9ebb5068bf19 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -18112,6 +18112,7 @@ package android.graphics.drawable {
method public void setThickness(@Px int);
method public void setThicknessRatio(@FloatRange(from=0.0f, fromInclusive=false) float);
method public void setUseLevel(boolean);
+ field @FlaggedApi("com.android.graphics.flags.gradient_drawable_shape_rounded_cap") public static final int ARC = 4; // 0x4
field public static final int LINE = 2; // 0x2
field public static final int LINEAR_GRADIENT = 0; // 0x0
field public static final int OVAL = 1; // 0x1
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f91b2474fdac..9e91f5944504 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2038,7 +2038,7 @@ public abstract class PackageManager {
public static final int INSTALL_SCENARIO_DEFAULT = 0;
/**
- * Installation scenario providing the fastest “install button to launch" experience possible.
+ * Installation scenario providing the fastest "install button to launch" experience possible.
*/
public static final int INSTALL_SCENARIO_FAST = 1;
@@ -3585,7 +3585,7 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device is
- * compatible with Android’s security model.
+ * compatible with Android's security model.
*
* <p>See sections 2 and 9 in the
* <a href="https://source.android.com/compatibility/android-cdd">Android CDD</a> for more
diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
index 74972346bf2e..3c03bb5626c8 100644
--- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java
+++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
@@ -130,7 +130,7 @@ public final class MessageQueue {
MessageQueue(boolean quitAllowed) {
initIsProcessAllowedToUseConcurrent();
- mUseConcurrent = sIsProcessAllowedToUseConcurrent;
+ mUseConcurrent = sIsProcessAllowedToUseConcurrent && !isInstrumenting();
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
mThread = Thread.currentThread();
@@ -202,6 +202,15 @@ public final class MessageQueue {
return;
}
+ private static boolean isInstrumenting() {
+ final ActivityThread activityThread = ActivityThread.currentActivityThread();
+ if (activityThread == null) {
+ return false;
+ }
+ final Instrumentation instrumentation = activityThread.getInstrumentation();
+ return instrumentation != null && instrumentation.isInstrumenting();
+ }
+
@Override
protected void finalize() throws Throwable {
try {
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index df680c054f56..fe868e1c43be 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -223,8 +223,14 @@ public class NotificationHeaderView extends RelativeLayout {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (notificationsRedesignTemplates()) {
- mTopLineTranslation = measureCenterTranslation(mTopLineView);
- mExpandButtonTranslation = measureCenterTranslation(mExpandButton);
+ // TODO: b/378660052 - These should never be null in practice, consider using
+ // requireViewById() in the onFinishInflate.
+ if (mTopLineView != null) {
+ mTopLineTranslation = measureCenterTranslation(mTopLineView);
+ }
+ if (mExpandButton != null) {
+ mExpandButtonTranslation = measureCenterTranslation(mExpandButton);
+ }
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0866e0d832b1..c048d7987515 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -66,6 +66,7 @@ import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFI
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION;
import static com.android.window.flags.Flags.FLAG_DELEGATE_UNHANDLED_DRAGS;
import static com.android.window.flags.Flags.FLAG_SUPPORTS_DRAG_ASSISTANT_TO_MULTIWINDOW;
+import static com.android.window.flags.Flags.reduceChangedExclusionRectsMsgs;
import static java.lang.Math.max;
@@ -247,6 +248,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
@@ -12888,15 +12890,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (rects.isEmpty() && mListenerInfo == null) return;
final ListenerInfo info = getListenerInfo();
+ final boolean rectsChanged = !reduceChangedExclusionRectsMsgs()
+ || !Objects.equals(info.mSystemGestureExclusionRects, rects);
if (info.mSystemGestureExclusionRects != null) {
- info.mSystemGestureExclusionRects.clear();
- info.mSystemGestureExclusionRects.addAll(rects);
+ if (rectsChanged) {
+ info.mSystemGestureExclusionRects.clear();
+ info.mSystemGestureExclusionRects.addAll(rects);
+ }
} else {
info.mSystemGestureExclusionRects = new ArrayList<>(rects);
}
-
- updatePositionUpdateListener();
- postUpdate(this::updateSystemGestureExclusionRects);
+ if (rectsChanged) {
+ updatePositionUpdateListener();
+ postUpdate(this::updateSystemGestureExclusionRects);
+ }
}
private void updatePositionUpdateListener() {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index cb9832282dc4..9498407fb33b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -136,6 +136,7 @@ import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay;
import static com.android.window.flags.Flags.enableWindowContextResourcesUpdateOnConfigChange;
import static com.android.window.flags.Flags.predictiveBackSwipeEdgeNoneApi;
+import static com.android.window.flags.Flags.reduceChangedExclusionRectsMsgs;
import static com.android.window.flags.Flags.setScPropertiesInClient;
import android.Manifest;
@@ -6074,8 +6075,12 @@ public final class ViewRootImpl implements ViewParent,
}
void updateSystemGestureExclusionRectsForView(View view) {
+ boolean msgInQueue = reduceChangedExclusionRectsMsgs()
+ && mGestureExclusionTracker.isWaitingForComputeChanges();
mGestureExclusionTracker.updateRectsForView(view);
- mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
+ if (!msgInQueue) {
+ mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
+ }
}
void systemGestureExclusionChanged() {
@@ -6119,8 +6124,12 @@ public final class ViewRootImpl implements ViewParent,
* the root's view hierarchy.
*/
public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) {
+ boolean msgInQueue = reduceChangedExclusionRectsMsgs()
+ && mGestureExclusionTracker.isWaitingForComputeChanges();
mGestureExclusionTracker.setRootRects(rects);
- mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
+ if (!msgInQueue) {
+ mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
+ }
}
/**
diff --git a/core/java/android/view/ViewRootRectTracker.java b/core/java/android/view/ViewRootRectTracker.java
index 152729b8d1d8..0bef3255f1dc 100644
--- a/core/java/android/view/ViewRootRectTracker.java
+++ b/core/java/android/view/ViewRootRectTracker.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.lang.ref.WeakReference;
@@ -32,8 +33,10 @@ import java.util.function.Function;
/**
* Abstract class to track a collection of rects reported by the views under the same
* {@link ViewRootImpl}.
+ * @hide
*/
-class ViewRootRectTracker {
+@VisibleForTesting
+public class ViewRootRectTracker {
private final Function<View, List<Rect>> mRectCollector;
private boolean mViewsChanged = false;
private boolean mRootRectsChanged = false;
@@ -41,11 +44,18 @@ class ViewRootRectTracker {
private List<ViewInfo> mViewInfos = new ArrayList<>();
private List<Rect> mRects = Collections.emptyList();
+ // Keeps track of whether updateRectsForView has been called but there was no subsequent call
+ // on computeChanges yet. Since updateRectsForView is called when sending a message and
+ // computeChanges when it is received, this tracks whether such message is in the queue already
+ private boolean mWaitingForComputeChanges = false;
+
/**
* @param rectCollector given a view returns a list of the rects of interest for this
* ViewRootRectTracker
+ * @hide
*/
- ViewRootRectTracker(Function<View, List<Rect>> rectCollector) {
+ @VisibleForTesting
+ public ViewRootRectTracker(Function<View, List<Rect>> rectCollector) {
mRectCollector = rectCollector;
}
@@ -70,6 +80,7 @@ class ViewRootRectTracker {
mViewInfos.add(new ViewInfo(view));
mViewsChanged = true;
}
+ mWaitingForComputeChanges = true;
}
/**
@@ -92,6 +103,7 @@ class ViewRootRectTracker {
* @return {@code true} if there were changes, {@code false} otherwise.
*/
public boolean computeChanges() {
+ mWaitingForComputeChanges = false;
boolean changed = mRootRectsChanged;
final Iterator<ViewInfo> i = mViewInfos.iterator();
final List<Rect> rects = new ArrayList<>(mRootRects);
@@ -121,6 +133,10 @@ class ViewRootRectTracker {
return false;
}
+ public boolean isWaitingForComputeChanges() {
+ return mWaitingForComputeChanges;
+ }
+
/**
* Returns a List of all Rects from all visible Views in the global (root) coordinate system.
* This list is only updated when calling {@link #computeChanges()} or
@@ -140,6 +156,7 @@ class ViewRootRectTracker {
Preconditions.checkNotNull(rects, "rects must not be null");
mRootRects = rects;
mRootRectsChanged = true;
+ mWaitingForComputeChanges = true;
}
@NonNull
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 891c5e382a58..3e3b8e100d6d 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -196,6 +196,16 @@ flag {
}
flag {
+ name: "enable_camera_compat_for_desktop_windowing_opt_out"
+ namespace: "lse_desktop_experience"
+ description: "Whether to allow developers to opt-out of Camera Compat treatment to fixed-orientation apps in desktop windowing mode"
+ bug: "328616176"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "enable_task_stack_observer_in_shell"
namespace: "lse_desktop_experience"
description: "Introduces a new observer in shell to track the task stack."
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 60f2c811dd1f..a4d128fa3caf 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -428,6 +428,17 @@ flag {
}
flag {
+ name: "reduce_changed_exclusion_rects_msgs"
+ namespace: "windowing_frontend"
+ description: "Don't send MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED when there is no change"
+ bug: "388231176"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "keep_app_window_hide_while_locked"
namespace: "windowing_frontend"
description: "Do not let app window visible while device is locked"
diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
index 2931bd2c83dd..fe616e085488 100644
--- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
@@ -16,6 +16,7 @@
package com.android.internal.os;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
@@ -155,8 +156,9 @@ public final class LongArrayMultiStateCounter implements Parcelable {
/**
* Adds the supplied values to the current accumulated values in the counter.
+ * Null `values` parameter is interpreted as an array of zeros.
*/
- public void incrementValues(long[] values, long timestampMs) {
+ public void incrementValues(@Nullable long[] values, long timestampMs) {
native_incrementValues(mNativeObject, values, timestampMs);
}
diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java
index 7030d8e84b70..4f5f37d0640e 100644
--- a/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java
@@ -16,6 +16,7 @@
package com.android.internal.os;
+import android.annotation.Nullable;
import android.os.BadParcelableException;
import android.os.Parcel;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
@@ -147,10 +148,12 @@ class LongArrayMultiStateCounter_ravenwood {
mLastUpdateTimestampMs = timestampMs;
}
- public void incrementValues(long[] delta, long timestampMs) {
+ public void incrementValues(@Nullable long[] delta, long timestampMs) {
long[] values = Arrays.copyOf(mValues, mValues.length);
- for (int i = 0; i < mArrayLength; i++) {
- values[i] += delta[i];
+ if (delta != null) {
+ for (int i = 0; i < mArrayLength; i++) {
+ values[i] += delta[i];
+ }
}
updateValue(values, timestampMs);
}
@@ -304,7 +307,8 @@ class LongArrayMultiStateCounter_ravenwood {
getInstance(targetInstanceId).copyStatesFrom(getInstance(sourceInstanceId));
}
- public static void native_incrementValues(long instanceId, long[] delta, long timestampMs) {
+ public static void native_incrementValues(long instanceId, @Nullable long[] delta,
+ long timestampMs) {
getInstance(instanceId).incrementValues(delta, timestampMs);
}
diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
index 7ee22f30ace0..69c04807c604 100644
--- a/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
@@ -157,7 +157,7 @@ public abstract class ParsedComponentImpl implements ParsedComponent, Parcelable
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(this.name);
+ sForInternedString.parcel(this.name, dest, flags);
dest.writeInt(this.getIcon());
dest.writeInt(this.getLabelRes());
dest.writeCharSequence(this.getNonLocalizedLabel());
@@ -175,7 +175,7 @@ public abstract class ParsedComponentImpl implements ParsedComponent, Parcelable
// We use the boot classloader for all classes that we load.
final ClassLoader boot = Object.class.getClassLoader();
//noinspection ConstantConditions
- this.name = in.readString();
+ this.name = sForInternedString.unparcel(in);
this.icon = in.readInt();
this.labelRes = in.readInt();
this.nonLocalizedLabel = in.readCharSequence();
diff --git a/core/java/com/android/internal/protolog/ProtoLogCommandHandler.java b/core/java/com/android/internal/protolog/ProtoLogCommandHandler.java
index 82d8d3431a9d..6d4a40899a65 100644
--- a/core/java/com/android/internal/protolog/ProtoLogCommandHandler.java
+++ b/core/java/com/android/internal/protolog/ProtoLogCommandHandler.java
@@ -145,11 +145,11 @@ public class ProtoLogCommandHandler extends ShellCommand {
switch (cmd) {
case "enable" -> {
- mProtoLogConfigurationService.enableProtoLogToLogcat(processGroups());
+ mProtoLogConfigurationService.enableProtoLogToLogcat(pw, processGroups());
return 0;
}
case "disable" -> {
- mProtoLogConfigurationService.disableProtoLogToLogcat(processGroups());
+ mProtoLogConfigurationService.disableProtoLogToLogcat(pw, processGroups());
return 0;
}
default -> {
diff --git a/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java b/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java
index d65aaae7deaa..a19690bbd0e4 100644
--- a/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java
+++ b/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java
@@ -18,6 +18,8 @@ package com.android.internal.protolog;
import android.annotation.NonNull;
+import java.io.PrintWriter;
+
public interface ProtoLogConfigurationService extends IProtoLogConfigurationService {
/**
* Get the list of groups clients have registered to the protolog service.
@@ -37,11 +39,11 @@ public interface ProtoLogConfigurationService extends IProtoLogConfigurationServ
* Enable logging target groups to logcat.
* @param groups we want to enable logging them to logcat for.
*/
- void enableProtoLogToLogcat(@NonNull String... groups);
+ void enableProtoLogToLogcat(@NonNull PrintWriter pw, @NonNull String... groups);
/**
* Disable logging target groups to logcat.
* @param groups we want to disable from being logged to logcat.
*/
- void disableProtoLogToLogcat(@NonNull String... groups);
+ void disableProtoLogToLogcat(@NonNull PrintWriter pw, @NonNull String... groups);
}
diff --git a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
index f83359dddfcc..ac1022ff1e0f 100644
--- a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java
@@ -44,6 +44,7 @@ import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -183,8 +184,8 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
* @param groups we want to enable logging them to logcat for.
*/
@Override
- public void enableProtoLogToLogcat(@NonNull String... groups) {
- toggleProtoLogToLogcat(true, groups);
+ public void enableProtoLogToLogcat(@NonNull PrintWriter pw, @NonNull String... groups) {
+ toggleProtoLogToLogcat(pw, true, groups);
}
/**
@@ -192,8 +193,8 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
* @param groups we want to disable from being logged to logcat.
*/
@Override
- public void disableProtoLogToLogcat(@NonNull String... groups) {
- toggleProtoLogToLogcat(false, groups);
+ public void disableProtoLogToLogcat(@NonNull PrintWriter pw, @NonNull String... groups) {
+ toggleProtoLogToLogcat(pw, false, groups);
}
/**
@@ -249,7 +250,9 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
}
}
- private void toggleProtoLogToLogcat(boolean enabled, @NonNull String[] groups) {
+ private void toggleProtoLogToLogcat(
+ @NonNull PrintWriter pw, boolean enabled, @NonNull String[] groups
+ ) {
final var clientToGroups = new HashMap<IProtoLogClient, Set<String>>();
for (String group : groups) {
@@ -257,8 +260,10 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
if (clients == null) {
// No clients associated to this group
- Log.w(LOG_TAG, "Attempting to toggle log to logcat for group " + group
- + " with no registered clients.");
+ var warning = "Attempting to toggle log to logcat for group " + group
+ + " with no registered clients. This is a no-op.";
+ Log.w(LOG_TAG, warning);
+ pw.println("WARNING: " + warning);
continue;
}
@@ -270,8 +275,14 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ
for (IProtoLogClient client : clientToGroups.keySet()) {
try {
- client.toggleLogcat(enabled, clientToGroups.get(client).toArray(new String[0]));
+ final var clientGroups = clientToGroups.get(client).toArray(new String[0]);
+ pw.println("Toggling logcat logging for client " + client.toString()
+ + " to " + enabled + " for groups: ["
+ + String.join(", ", clientGroups) + "]");
+ client.toggleLogcat(enabled, clientGroups);
+ pw.println("- Done");
} catch (RemoteException e) {
+ pw.println("- Failed");
throw new RuntimeException(
"Failed to toggle logcat status for groups on client", e);
}
diff --git a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
index 7ffe0ed7c6cd..8f36ecb8b01a 100644
--- a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
+++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
@@ -97,7 +97,13 @@ static void native_updateValues(JNIEnv *env, jclass, jlong nativePtr, jlongArray
static void native_incrementValues(JNIEnv *env, jclass, jlong nativePtr, jlongArray values,
jlong timestamp) {
auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr);
- counter->incrementValue(JavaUint64Array(env, values), timestamp);
+ if (values != nullptr) {
+ counter->incrementValue(JavaUint64Array(env, values), timestamp);
+ } else {
+ // Pass an empty Uint64Array, which is equivalent to an array of zeros.
+ // This is done to ensure that the timestamp is still updated in the counter.
+ counter->incrementValue(Uint64Array(), timestamp);
+ }
}
static void native_addCounts(JNIEnv *env, jclass, jlong nativePtr, jlongArray values) {
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index b51f72dee260..aa8f8419ac46 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -5,7 +5,6 @@ joeo@google.com
singhtejinder@google.com
yanmin@google.com
yaochen@google.com
-yro@google.com
zhouwenjie@google.com
# Frameworks
diff --git a/core/res/res/drawable/progress_ring_watch.xml b/core/res/res/drawable/progress_ring_watch.xml
index 8250ee600a8f..2e65ff13b3de 100644
--- a/core/res/res/drawable/progress_ring_watch.xml
+++ b/core/res/res/drawable/progress_ring_watch.xml
@@ -16,27 +16,27 @@
-->
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
- android:fromDegrees = "270"
- android:toDegrees="270"
- android:pivotX="50%"
- android:pivotY="50%" >
+ android:fromDegrees="270"
+ android:toDegrees="270">
<layer-list>
<item>
<shape
- android:shape="ring"
- android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio"
+ android:shape="arc"
+ android:useLevel="false"
android:thickness="@dimen/progressbar_thickness"
- android:useLevel="false">
- <solid android:color="@color/materialColorSurfaceContainer"/>
+ android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio"
+ android:strokeCap="round">
+ <solid android:color="@*android:color/materialColorSurfaceContainer"/>
</shape>
</item>
<item>
<shape
- android:shape="ring"
- android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio"
+ android:shape="arc"
+ android:useLevel="true"
android:thickness="@dimen/progressbar_thickness"
- android:useLevel="true">
- <solid android:color="@color/materialColorPrimary"/>
+ android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio"
+ android:strokeCap="round">
+ <solid android:color="@*android:color/materialColorPrimary"/>
</shape>
</item>
</layer-list>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 66111785af4f..d2c993aecb0d 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -6934,6 +6934,8 @@
<enum name="line" value="2" />
<!-- Ring shape. -->
<enum name="ring" value="3" />
+ <!-- ARC shape. -->
+ <enum name="arc" value="4"/>
</attr>
<!-- Inner radius of the ring expressed as a ratio of the ring's width. For instance,
if innerRadiusRatio=9, then the inner radius equals the ring's width divided by 9.
@@ -6966,6 +6968,12 @@
<attr name="opticalInsetRight" />
<!-- Bottom optical inset. -->
<attr name="opticalInsetBottom" />
+ <!-- Attributes that customize the stroke line cap. @hide -->
+ <attr name="strokeCap" format="enum">
+ <enum name="butt" value="0"/>
+ <enum name="round" value="1"/>
+ <enum name="square" value="2"/>
+ </attr>
</declare-styleable>
<!-- Used to specify the size of the shape for GradientDrawable. -->
diff --git a/core/res/res/values/dimens_watch.xml b/core/res/res/values/dimens_watch.xml
index 2aae98715973..7462b733b0ae 100644
--- a/core/res/res/values/dimens_watch.xml
+++ b/core/res/res/values/dimens_watch.xml
@@ -52,7 +52,7 @@
<dimen name="primary_content_alpha_device_default">0.38</dimen>
<!-- values for wear material3 progress bar(progress indicator) -->
- <item name="progressbar_inner_radius_ratio" format="float" type="dimen">2.12</item>
+ <item name="progressbar_inner_radius_ratio" format="float" type="dimen">2</item>
<dimen name="progressbar_thickness">8dp</dimen>
<dimen name="progressbar_elevation">0.1dp</dimen>
diff --git a/core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java b/core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java
new file mode 100644
index 000000000000..c66e10079bc8
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.testng.AssertJUnit.assertEquals;
+
+import android.graphics.Rect;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.google.common.collect.Lists;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ViewRootRectTrackerTest {
+ private ViewRootRectTracker mTracker;
+ private final List<Rect> mRects = Lists.newArrayList(new Rect(0, 0, 5, 5),
+ new Rect(5, 5, 10, 10));
+
+ @Before
+ public void setUp() {
+ mTracker = new ViewRootRectTracker(v -> Collections.emptyList());
+ }
+
+ @Test
+ public void setRootRectsAndComputeTest() {
+ mTracker.setRootRects(mRects);
+ mTracker.computeChanges();
+ assertEquals(mRects, mTracker.getLastComputedRects());
+ }
+
+ @Test
+ public void waitingForComputeChangesTest() {
+ mTracker.setRootRects(mRects);
+ assertTrue(mTracker.isWaitingForComputeChanges());
+ mTracker.computeChangedRects();
+ assertFalse(mTracker.isWaitingForComputeChanges());
+
+ View mockView = mock(View.class);
+ mTracker.updateRectsForView(mockView);
+ assertTrue(mTracker.isWaitingForComputeChanges());
+ mTracker.computeChangedRects();
+ assertFalse(mTracker.isWaitingForComputeChanges());
+ }
+}
diff --git a/graphics/java/android/framework_graphics.aconfig b/graphics/java/android/framework_graphics.aconfig
index a63cbee4d707..fdbee3ccbebe 100644
--- a/graphics/java/android/framework_graphics.aconfig
+++ b/graphics/java/android/framework_graphics.aconfig
@@ -42,3 +42,11 @@ flag {
description: "Add DISPLAY_BT2020 ColorSpace support"
bug: "344038816"
}
+
+flag {
+ name: "gradient_drawable_shape_rounded_cap"
+ is_fixed_read_only: true
+ namespace: "core_graphics"
+ description: "Make GradientDrawable support drawing ring with rounded stroke cap."
+ bug: "380000245"
+}
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 29d033e64aea..ff1dc93d787b 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -16,7 +16,11 @@
package android.graphics.drawable;
+import static com.android.graphics.flags.Flags.FLAG_GRADIENT_DRAWABLE_SHAPE_ROUNDED_CAP;
+import static com.android.graphics.flags.Flags.gradientDrawableShapeRoundedCap;
+
import android.annotation.ColorInt;
+import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -125,8 +129,14 @@ public class GradientDrawable extends Drawable {
*/
public static final int RING = 3;
+ /**
+ * Shape is an arc.
+ */
+ @FlaggedApi(FLAG_GRADIENT_DRAWABLE_SHAPE_ROUNDED_CAP)
+ public static final int ARC = 4;
+
/** @hide */
- @IntDef({RECTANGLE, OVAL, LINE, RING})
+ @IntDef({RECTANGLE, OVAL, LINE, RING, ARC})
@Retention(RetentionPolicy.SOURCE)
public @interface Shape {}
@@ -167,6 +177,17 @@ public class GradientDrawable extends Drawable {
@Retention(RetentionPolicy.SOURCE)
public @interface RadiusType {}
+ private static final int BUTT = 0;
+
+ private static final int ROUND = 1;
+
+ private static final int SQUARE = 2;
+
+ /** @hide */
+ @IntDef({BUTT, ROUND, SQUARE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StrokeCap {}
+
private static final float DEFAULT_INNER_RADIUS_RATIO = 3.0f;
private static final float DEFAULT_THICKNESS_RATIO = 9.0f;
@@ -191,6 +212,8 @@ public class GradientDrawable extends Drawable {
private boolean mMutated;
private Path mRingPath;
private boolean mPathIsDirty = true;
+ private Path mArcPath;
+ private Path mArcOutlinePath;
/** Current gradient radius, valid when {@link #mGradientIsDirty} is false. */
private float mGradientRadius;
@@ -850,6 +873,55 @@ public class GradientDrawable extends Drawable {
}
break;
}
+ case ARC:
+ if (gradientDrawableShapeRoundedCap()) {
+ // TODO(b/394988176): Consider applying ARC drawing logic to RING shape.
+ float centerX = mRect.centerX();
+ float centerY = mRect.centerY();
+ float thickness =
+ st.mThickness != -1 ? st.mThickness
+ : mRect.width() / st.mThicknessRatio;
+ float radius = st.mInnerRadius != -1 ? st.mInnerRadius
+ : mRect.width() / st.mInnerRadiusRatio;
+ radius -= thickness;
+ float sweep = st.mUseLevelForShape ? (360.0f * getLevel() / 10000.0f) : 360f;
+ mRect.set(centerX - radius, centerY - radius, centerX + radius,
+ centerY + radius);
+
+ // Prepare paint. Set style to STROKE for purpose of drawing line ARC.
+ mFillPaint.setStyle(Paint.Style.STROKE);
+ mFillPaint.setStrokeWidth(thickness);
+ mFillPaint.setStrokeCap(getStrokeLineCapForPaint(st.mStrokeCap));
+ canvas.drawArc(mRect, 0.0f, sweep, /* useCenter= */ false, mFillPaint);
+
+ if (haveStroke) {
+ if (mArcPath == null) {
+ mArcPath = new Path();
+ } else {
+ mArcPath.reset();
+ }
+ if (mArcOutlinePath == null) {
+ mArcOutlinePath = new Path();
+ } else {
+ mArcOutlinePath.reset();
+ }
+ if (sweep == 360f) {
+ mArcPath.addOval(mRect, Path.Direction.CW);
+ } else {
+ mArcPath.arcTo(mRect, 0.0f, sweep, /* forceMoveTo= */ false);
+ }
+
+ // The arc path doesn't have width. So, to get the outline of the result arc
+ // shape, we need to apply the paint effect to the path; then use the
+ // output as the result outline.
+ mFillPaint.getFillPath(mArcPath, mArcOutlinePath);
+ canvas.drawPath(mArcOutlinePath, mStrokePaint);
+ }
+
+ // Restore to FILL
+ mFillPaint.setStyle(Paint.Style.FILL);
+ break;
+ }
case RING:
Path path = buildRing(st);
canvas.drawPath(path, mFillPaint);
@@ -993,6 +1065,36 @@ public class GradientDrawable extends Drawable {
}
/**
+ * Return current drawable's stroke line cap. Note that this is only respected when drawable is
+ * {@link Shape#ARC}.
+ *
+ * @return the {@link StrokeCap} of current drawable.
+ * @attr ref android.R.styleable#GradientDrawable_strokeCap
+ * @see #setStrokeCap(int)
+ *
+ * @hide
+ */
+ @StrokeCap
+ public int getStrokeCap() {
+ return mGradientState.mStrokeCap;
+ }
+
+ /**
+ * Configure the stroke line cap type that drawable will use while drawing. Note that this is
+ * only respected when drawable is {@link Shape#ARC}.
+ *
+ * @param strokeCapType the stroke line cap type that the drawable will use while drawing.
+ * @attr ref android.R.styleable#GradientDrawable_strokeCap
+ * @see #getStrokeCap
+ *
+ * @hide
+ */
+ public void setStrokeCap(@StrokeCap int strokeCapType) {
+ mGradientState.mStrokeCap = strokeCapType;
+ invalidateSelf();
+ }
+
+ /**
* Configure the padding of the gradient shape
* @param left Left padding of the gradient shape
* @param top Top padding of the gradient shape
@@ -1066,6 +1168,15 @@ public class GradientDrawable extends Drawable {
return ringPath;
}
+ private Paint.Cap getStrokeLineCapForPaint(@StrokeCap int strokeLineCap) {
+ return switch (strokeLineCap) {
+ case BUTT -> Paint.Cap.BUTT;
+ case ROUND -> Paint.Cap.ROUND;
+ case SQUARE -> Paint.Cap.SQUARE;
+ default -> Paint.Cap.SQUARE;
+ };
+ }
+
/**
* Changes this drawable to use a single color instead of a gradient.
* <p>
@@ -1484,7 +1595,7 @@ public class GradientDrawable extends Drawable {
state.mShape = a.getInt(R.styleable.GradientDrawable_shape, state.mShape);
state.mDither = a.getBoolean(R.styleable.GradientDrawable_dither, state.mDither);
- if (state.mShape == RING) {
+ if (state.mShape == RING || state.mShape == ARC) {
state.mInnerRadius = a.getDimensionPixelSize(
R.styleable.GradientDrawable_innerRadius, state.mInnerRadius);
@@ -1503,6 +1614,9 @@ public class GradientDrawable extends Drawable {
state.mUseLevelForShape = a.getBoolean(
R.styleable.GradientDrawable_useLevel, state.mUseLevelForShape);
+
+ state.mStrokeCap = a.getInt(
+ R.styleable.GradientDrawable_strokeCap, state.mStrokeCap);
}
final int tintMode = a.getInt(R.styleable.GradientDrawable_tintMode, -1);
@@ -2045,6 +2159,9 @@ public class GradientDrawable extends Drawable {
public int mInnerRadius = -1;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050218)
public int mThickness = -1;
+ @UnsupportedAppUsage(trackingBug = 380000245)
+ @StrokeCap public int mStrokeCap = ROUND;
+
public boolean mDither = false;
public Insets mOpticalInsets = Insets.NONE;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index f6a2c8d9695e..305fcdd5fb7d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -912,7 +912,7 @@ public class BubbleController implements ConfigurationChangeListener,
// TODO(b/393172431) : Utilise DragZoneFactory once it is ready
final int bubbleBarDropZoneSideSize = getContext().getResources().getDimensionPixelSize(
R.dimen.bubble_bar_drop_zone_side_size);
- int top = t - bubbleBarDropZoneSideSize;
+ int top = b - bubbleBarDropZoneSideSize;
result.put(BubbleBarLocation.LEFT,
new Rect(l, top, l + bubbleBarDropZoneSideSize, b));
result.put(BubbleBarLocation.RIGHT,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index e3b0872df593..29837dc04423 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -135,6 +135,7 @@ public class BubbleBarLayerView extends FrameLayout
/** Shows the expanded view drop target at the requested {@link BubbleBarLocation location} */
public void showBubbleBarExtendedViewDropTarget(@NonNull BubbleBarLocation bubbleBarLocation) {
+ setVisibility(VISIBLE);
mBubbleExpandedViewPinController.showDropTarget(bubbleBarLocation);
}
diff --git a/packages/SettingsLib/AndroidManifest.xml b/packages/SettingsLib/AndroidManifest.xml
index 412ff29aec32..473b7eb07666 100644
--- a/packages/SettingsLib/AndroidManifest.xml
+++ b/packages/SettingsLib/AndroidManifest.xml
@@ -21,6 +21,13 @@
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<application>
+ <activity
+ android:name=".users.CreateUserActivity"
+ android:excludeFromRecents="true"
+ android:exported="false"
+ android:finishOnCloseSystemDialogs="true"
+ android:launchMode="singleInstance"
+ android:theme="@style/Theme.Transparent"/>
</application>
</manifest>
diff --git a/packages/SettingsLib/IllustrationPreference/AndroidManifest.xml b/packages/SettingsLib/IllustrationPreference/AndroidManifest.xml
index a0d10c383445..56b05159a30f 100644
--- a/packages/SettingsLib/IllustrationPreference/AndroidManifest.xml
+++ b/packages/SettingsLib/IllustrationPreference/AndroidManifest.xml
@@ -18,6 +18,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.settingslib.widget.preference.illustration">
- <uses-sdk android:minSdkVersion="28" />
+ <uses-sdk android:minSdkVersion="30" />
</manifest>
diff --git a/packages/SettingsLib/IllustrationPreference/res/values/strings.xml b/packages/SettingsLib/IllustrationPreference/res/values/strings.xml
new file mode 100644
index 000000000000..3a8aaf8b5092
--- /dev/null
+++ b/packages/SettingsLib/IllustrationPreference/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Label for an accessibility action that starts an animation [CHAR LIMIT=30] -->
+ <string name="settingslib_action_label_resume">resume</string>
+ <!-- Label for an accessibility action that stops an animation [CHAR LIMIT=30] -->
+ <string name="settingslib_action_label_pause">pause</string>
+ <!-- Label for an accessibility action that stops an animation [CHAR LIMIT=50] -->
+ <string name="settingslib_state_animation_playing">Animation playing</string>
+ <!-- Label for an accessibility action that stops an animation [CHAR LIMIT=50] -->
+ <string name="settingslib_state_animation_paused">Animation paused</string>
+</resources>
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
index af40c647e805..e818a603c5b4 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -32,6 +32,8 @@ import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -73,6 +75,7 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
private boolean mLottieDynamicColor;
private CharSequence mContentDescription;
private boolean mIsTablet;
+ private boolean mIsAnimatable;
private boolean mIsAnimationPaused;
/**
@@ -81,6 +84,7 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
public interface OnBindListener {
/**
* Called when when {@link #onBindViewHolder(PreferenceViewHolder)} occurs.
+ *
* @param animationView the animation view for this preference.
*/
void onBind(LottieAnimationView animationView);
@@ -144,16 +148,6 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
(FrameLayout) holder.findViewById(R.id.middleground_layout);
final LottieAnimationView illustrationView =
(LottieAnimationView) holder.findViewById(R.id.lottie_view);
- // Pause and resume animation
- illustrationFrame.setOnClickListener(v -> {
- mIsAnimationPaused = !mIsAnimationPaused;
- if (mIsAnimationPaused) {
- illustrationView.pauseAnimation();
- } else {
- illustrationView.resumeAnimation();
- }
- });
-
if (illustrationView != null && !TextUtils.isEmpty(mContentDescription)) {
illustrationView.setContentDescription(mContentDescription);
illustrationView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
@@ -171,12 +165,13 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
illustrationView.setCacheComposition(mCacheComposition);
handleImageWithAnimation(illustrationView, illustrationFrame);
+ handleAnimationControl(illustrationView, illustrationFrame);
handleImageFrameMaxHeight(backgroundView, illustrationView);
if (mIsAutoScale) {
illustrationView.setScaleType(mIsAutoScale
- ? ImageView.ScaleType.CENTER_CROP
- : ImageView.ScaleType.CENTER_INSIDE);
+ ? ImageView.ScaleType.CENTER_CROP
+ : ImageView.ScaleType.CENTER_INSIDE);
}
handleMiddleGroundView(middleGroundLayout);
@@ -377,6 +372,7 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
final Drawable drawable = illustrationView.getDrawable();
if (drawable != null) {
startAnimation(drawable);
+ mIsAnimatable = false;
}
}
@@ -386,10 +382,12 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
final Drawable drawable = illustrationView.getDrawable();
if (drawable != null) {
startAnimation(drawable);
+ mIsAnimatable = false;
} else {
// The lottie image from the raw folder also returns null because the ImageView
// couldn't handle it now.
startLottieAnimationWith(illustrationView, mImageUri);
+ mIsAnimatable = true;
}
}
@@ -418,10 +416,12 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
final Drawable drawable = illustrationView.getDrawable();
if (drawable != null) {
startAnimation(drawable);
+ mIsAnimatable = false;
} else {
// The lottie image from the raw folder also returns null because the ImageView
// couldn't handle it now.
startLottieAnimationWith(illustrationView, mImageResId);
+ mIsAnimatable = true;
}
}
}
@@ -459,6 +459,60 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
((Animatable) drawable).start();
}
+ private void handleAnimationControl(LottieAnimationView illustrationView,
+ ViewGroup container) {
+ if (mIsAnimatable) {
+ // TODO(b/397340540): list out pages having illustration without a content description.
+ if (TextUtils.isEmpty(mContentDescription)) {
+ Log.w(TAG, "Illustration should have a content description. preference key = "
+ + getKey());
+ }
+ // Enable pause and resume abilities to animation only
+ container.setOnClickListener(v -> {
+ mIsAnimationPaused = !mIsAnimationPaused;
+ if (mIsAnimationPaused) {
+ illustrationView.pauseAnimation();
+ } else {
+ illustrationView.resumeAnimation();
+ }
+ updateAccessibilityAction(container);
+ });
+
+ updateAccessibilityAction(container);
+ }
+ }
+
+ private void updateAccessibilityAction(ViewGroup container) {
+ // Setting the state of animation
+ container.setStateDescription(getStateDescriptionForAnimation());
+ container.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ final AccessibilityAction clickAction = new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLICK,
+ getActionLabelForAnimation());
+ info.addAction(clickAction);
+ }
+ });
+ }
+
+ private String getActionLabelForAnimation() {
+ if (mIsAnimationPaused) {
+ return getContext().getString(R.string.settingslib_action_label_resume);
+ } else {
+ return getContext().getString(R.string.settingslib_action_label_pause);
+ }
+ }
+
+ private String getStateDescriptionForAnimation() {
+ if (mIsAnimationPaused) {
+ return getContext().getString(R.string.settingslib_state_animation_paused);
+ } else {
+ return getContext().getString(R.string.settingslib_state_animation_playing);
+ }
+ }
+
private static void startLottieAnimationWith(LottieAnimationView illustrationView,
Uri imageUri) {
final InputStream inputStream =
@@ -514,15 +568,20 @@ public class IllustrationPreference extends Preference implements GroupSectionDi
mIsAutoScale = false;
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs,
- com.airbnb.lottie.R.styleable.LottieAnimationView, 0 /*defStyleAttr*/, 0 /*defStyleRes*/);
- mImageResId = a.getResourceId(com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_rawRes, 0);
+ com.airbnb.lottie.R.styleable.LottieAnimationView, /* defStyleAttr= */ 0,
+ /* defStyleRes= */ 0);
+ mImageResId = a.getResourceId(
+ com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_rawRes,
+ /* defValue= */ 0);
mCacheComposition = a.getBoolean(
- com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_cacheComposition, true);
+ com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_cacheComposition,
+ /* defValue= */ true);
a = context.obtainStyledAttributes(attrs,
- R.styleable.IllustrationPreference, 0 /*defStyleAttr*/, 0 /*defStyleRes*/);
+ R.styleable.IllustrationPreference, /* defStyleAttr= */ 0,
+ /* defStyleRes= */ 0);
mLottieDynamicColor = a.getBoolean(R.styleable.IllustrationPreference_dynamicColor,
- false);
+ /* defValue= */ false);
a.recycle();
}
diff --git a/packages/SettingsLib/res/layout/activity_create_new_user.xml b/packages/SettingsLib/res/layout/activity_create_new_user.xml
new file mode 100644
index 000000000000..7453b53a6956
--- /dev/null
+++ b/packages/SettingsLib/res/layout/activity_create_new_user.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2025 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent"
+ android:orientation="vertical">
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml
index 3326b6034237..7ab096fae0db 100644
--- a/packages/SettingsLib/res/values/styles.xml
+++ b/packages/SettingsLib/res/values/styles.xml
@@ -116,4 +116,13 @@
<item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
<item name="android:textSize">16dp</item>
</style>
+
+ <style name="Theme.Transparent" parent="@android:style/Theme.DeviceDefault.Settings">
+ <item name="android:windowActionBar">false</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java
new file mode 100644
index 000000000000..c5e6f60e3fa6
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2025 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.users;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.MotionEvent;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.R;
+
+
+public class CreateUserActivity extends Activity {
+ private static final String TAG = "CreateUserActivity";
+
+ public static final String EXTRA_USER_NAME = "new_user_name";
+ public static final String EXTRA_IS_ADMIN = "is_admin";
+ public static final String EXTRA_USER_ICON_PATH = "user_icon_path";
+ private static final String DIALOG_STATE_KEY = "create_user_dialog_state";
+ private static final String EXTRA_CAN_CREATE_ADMIN = "can_create_admin";
+ private static final String EXTRA_FILE_AUTHORITY = "file_authority";
+
+ private CreateUserDialogController mCreateUserDialogController;
+ @VisibleForTesting
+ Dialog mSetupUserDialog;
+
+
+ /**
+ * Creates intent to start CreateUserActivity
+ */
+ public static @NonNull Intent createIntentForStart(@NonNull Context context,
+ boolean canCreateAdminUser, @NonNull String fileAuth) {
+ Intent intent = new Intent(context, CreateUserActivity.class);
+ intent.putExtra(EXTRA_CAN_CREATE_ADMIN, canCreateAdminUser);
+ intent.putExtra(EXTRA_FILE_AUTHORITY, fileAuth);
+ return intent;
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Intent intent = getIntent();
+
+ mCreateUserDialogController = new CreateUserDialogController(
+ intent.getStringExtra(EXTRA_FILE_AUTHORITY));
+ setContentView(R.layout.activity_create_new_user);
+ if (savedInstanceState != null) {
+ mCreateUserDialogController.onRestoreInstanceState(savedInstanceState);
+ }
+ mSetupUserDialog = createDialog(intent.getBooleanExtra(EXTRA_CAN_CREATE_ADMIN, false));
+ mSetupUserDialog.show();
+ }
+
+ @Override
+ protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ Bundle savedDialogState = savedInstanceState.getBundle(DIALOG_STATE_KEY);
+ if (savedDialogState != null && mSetupUserDialog != null) {
+ mSetupUserDialog.onRestoreInstanceState(savedDialogState);
+ }
+ }
+
+ private Dialog createDialog(boolean canCreateAdminUser) {
+ return mCreateUserDialogController.createDialog(
+ this,
+ this::startActivity,
+ canCreateAdminUser,
+ this::setSuccessResult,
+ this::cancel
+ );
+ }
+
+ @Override
+ public boolean onTouchEvent(@Nullable MotionEvent event) {
+ onBackInvoked();
+ return super.onTouchEvent(event);
+ }
+
+ private void onBackInvoked() {
+ if (mSetupUserDialog != null) {
+ mSetupUserDialog.dismiss();
+ }
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+
+ @VisibleForTesting
+ void setSuccessResult(String userName, Drawable userIcon, String path, Boolean isAdmin) {
+ Intent intent = new Intent(this, CreateUserActivity.class);
+ intent.putExtra(EXTRA_USER_NAME, userName);
+ intent.putExtra(EXTRA_IS_ADMIN, isAdmin);
+ intent.putExtra(EXTRA_USER_ICON_PATH, path);
+
+ mSetupUserDialog.dismiss();
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+
+ @VisibleForTesting
+ void cancel() {
+ mSetupUserDialog.dismiss();
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+
+ @Override
+ protected void onSaveInstanceState(@NonNull Bundle outState) {
+ if (mSetupUserDialog != null && mSetupUserDialog.isShowing()) {
+ outState.putBundle(DIALOG_STATE_KEY, mSetupUserDialog.onSaveInstanceState());
+ }
+ mCreateUserDialogController.onSaveInstanceState(outState);
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ mCreateUserDialogController.onActivityResult(requestCode, resultCode, data);
+ }
+
+ private void startActivity(Intent intent, int requestCode) {
+ startActivityForResult(intent, requestCode);
+ mCreateUserDialogController.startingActivityForResult();
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java
index d71b337228f6..d9f1b632323c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java
@@ -242,7 +242,7 @@ public class CreateUserDialogController {
.setMessage(messageResId)
.setNegativeButtonText(R.string.cancel)
.setPositiveButtonText(R.string.next);
- mCustomDialogHelper.requestFocusOnTitle();
+ focus();
break;
case GRANT_ADMIN_DIALOG:
mEditUserInfoView.setVisibility(View.GONE);
@@ -255,7 +255,7 @@ public class CreateUserDialogController {
.setMessage(R.string.user_grant_admin_message)
.setNegativeButtonText(R.string.back)
.setPositiveButtonText(R.string.next);
- mCustomDialogHelper.requestFocusOnTitle();
+ focus();
if (mIsAdmin == null) {
mCustomDialogHelper.setButtonEnabled(false);
}
@@ -267,7 +267,7 @@ public class CreateUserDialogController {
.setTitle(R.string.user_info_settings_title)
.setNegativeButtonText(R.string.back)
.setPositiveButtonText(R.string.done);
- mCustomDialogHelper.requestFocusOnTitle();
+ focus();
mEditUserInfoView.setVisibility(View.VISIBLE);
mGrantAdminView.setVisibility(View.GONE);
break;
@@ -282,7 +282,7 @@ public class CreateUserDialogController {
mCustomDialogHelper.getDialog().dismiss();
break;
case EXIT_DIALOG:
- mCustomDialogHelper.getDialog().dismiss();
+ finish();
break;
default:
if (mCurrentState < EXIT_DIALOG) {
@@ -394,13 +394,21 @@ public class CreateUserDialogController {
return mCustomDialogHelper != null && mCustomDialogHelper.getDialog() != null;
}
+ void focus() {
+ mCustomDialogHelper.requestFocusOnTitle();
+ }
+
/**
* Runs callback and clears saved values after dialog is dismissed.
*/
public void finish() {
if (mCurrentState == CREATE_USER_AND_CLOSE) {
if (mSuccessCallback != null) {
- mSuccessCallback.onSuccess(mUserName, mNewUserIcon, Boolean.TRUE.equals(mIsAdmin));
+ if (mEditUserPhotoController != null && mCachedDrawablePath == null) {
+ mCachedDrawablePath = mEditUserPhotoController.getCachedDrawablePath();
+ }
+ mSuccessCallback.onSuccess(mUserName, mNewUserIcon, mCachedDrawablePath,
+ Boolean.TRUE.equals(mIsAdmin));
}
} else {
if (mCancelCallback != null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/NewUserData.java b/packages/SettingsLib/src/com/android/settingslib/users/NewUserData.java
index 3d18b59258b3..eed608e98cc9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/NewUserData.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/NewUserData.java
@@ -18,6 +18,8 @@ package com.android.settingslib.users;
import android.graphics.drawable.Drawable;
+import androidx.annotation.Nullable;
+
/**
* Defines a callback when a new user data is filled out.
*/
@@ -27,8 +29,10 @@ public interface NewUserData {
* Consumes data relevant to new user that needs to be created.
* @param userName New user name.
* @param userImage New user icon.
+ * @param iconPath New user icon path.
* @param isNewUserAdmin A boolean that indicated whether new user has admin status.
*/
- void onSuccess(String userName, Drawable userImage, Boolean isNewUserAdmin);
+ void onSuccess(@Nullable String userName, @Nullable Drawable userImage,
+ @Nullable String iconPath, @Nullable Boolean isNewUserAdmin);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java
new file mode 100644
index 000000000000..f58eb7cc2e31
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2025 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.users;
+
+import static com.android.settingslib.users.CreateUserActivity.EXTRA_IS_ADMIN;
+import static com.android.settingslib.users.CreateUserActivity.EXTRA_USER_ICON_PATH;
+import static com.android.settingslib.users.CreateUserActivity.EXTRA_USER_NAME;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.MotionEvent;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class CreateUserActivityTest {
+
+ private static final String TEST_USER_NAME = "test_user";
+ private static final String TEST_USER_ICON_PATH = "/test_path";
+ private static final boolean TEST_IS_ADMIN = true;
+
+ private Context mContext;
+ private CreateUserActivity mCreateUserActivity;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mCreateUserActivity = Robolectric.buildActivity(CreateUserActivity.class).setup().get();
+ }
+
+ @Test
+ public void startActivity_startsActivityForResult() {
+ Intent activityIntent = CreateUserActivity.createIntentForStart(mContext, true, "");
+ mCreateUserActivity.startActivity(activityIntent, null);
+
+ assertThat(shadowOf(mCreateUserActivity).getNextStartedActivityForResult().intent)
+ .isEqualTo(activityIntent);
+ }
+
+ @Test
+ public void onTouchEvent_dismissesDialogAndCancelsResult() {
+ mCreateUserActivity.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0,
+ 0));
+
+ assertThat(mCreateUserActivity.mSetupUserDialog.isShowing()).isFalse();
+ assertThat(shadowOf(mCreateUserActivity).getResultCode())
+ .isEqualTo(Activity.RESULT_CANCELED);
+ }
+
+ @Test
+ public void setSuccessResult_dismissesDialogAndSetsSuccessResult() {
+ Drawable mockDrawable = mock(Drawable.class);
+
+ mCreateUserActivity.setSuccessResult(TEST_USER_NAME, mockDrawable, TEST_USER_ICON_PATH,
+ TEST_IS_ADMIN);
+
+ assertThat(mCreateUserActivity.mSetupUserDialog.isShowing()).isFalse();
+ assertThat(shadowOf(mCreateUserActivity).getResultCode()).isEqualTo(Activity.RESULT_OK);
+
+ Intent resultIntent = shadowOf(mCreateUserActivity).getResultIntent();
+ assertThat(resultIntent.getStringExtra(EXTRA_USER_NAME)).isEqualTo(TEST_USER_NAME);
+ assertThat(resultIntent.getBooleanExtra(EXTRA_IS_ADMIN, false)).isEqualTo(TEST_IS_ADMIN);
+ assertThat(resultIntent.getStringExtra(EXTRA_USER_ICON_PATH))
+ .isEqualTo(TEST_USER_ICON_PATH);
+ }
+
+ @Test
+ public void cancel_dismissesDialogAndSetsCancelResult() {
+ mCreateUserActivity.cancel();
+
+ assertThat(mCreateUserActivity.mSetupUserDialog.isShowing()).isFalse();
+ assertThat(shadowOf(mCreateUserActivity).getResultCode())
+ .isEqualTo(Activity.RESULT_CANCELED);
+ }
+
+ @Test
+ public void onSaveInstanceState_savesDialogState() {
+ Bundle outState = new Bundle();
+ mCreateUserActivity.onSaveInstanceState(outState);
+
+ CreateUserActivity restoredActivity =
+ Robolectric.buildActivity(CreateUserActivity.class).setup(outState).get();
+
+ assertThat(restoredActivity.mSetupUserDialog).isNotNull();
+ assertThat(restoredActivity.mSetupUserDialog.isShowing()).isTrue();
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java
index 68312223b4b1..e60232339e4c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java
@@ -211,7 +211,7 @@ public class CreateUserDialogControllerTest {
editText.setText(expectedNewName);
next.performClick();
verify(successCallback, times(1))
- .onSuccess(expectedNewName, null, true);
+ .onSuccess(expectedNewName, null, null, true);
verifyNoInteractions(cancelCallback);
}
@@ -233,7 +233,7 @@ public class CreateUserDialogControllerTest {
editText.setText(expectedNewName);
next.performClick();
verify(successCallback, times(1))
- .onSuccess(expectedNewName, null, false);
+ .onSuccess(expectedNewName, null, null, false);
verifyNoInteractions(cancelCallback);
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 8e3aa65fa5c7..bc281eea39d8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1503,7 +1503,7 @@ public class SettingsProvider extends ContentProvider {
if (DEBUG) {
Slog.v(LOG_TAG, "insertGlobalSetting(" + name + ", " + value + ", "
+ ", " + tag + ", " + makeDefault + ", " + requestingUserId
- + ", " + forceNotify + ")");
+ + ", " + forceNotify + ", " + overrideableByRestore + ")");
}
return mutateGlobalSetting(name, value, tag, makeDefault, requestingUserId,
MUTATION_OPERATION_INSERT, forceNotify, 0, overrideableByRestore);
@@ -1785,7 +1785,7 @@ public class SettingsProvider extends ContentProvider {
if (DEBUG) {
Slog.v(LOG_TAG, "insertSecureSetting(" + name + ", " + value + ", "
+ ", " + tag + ", " + makeDefault + ", " + requestingUserId
- + ", " + forceNotify + ")");
+ + ", " + forceNotify + ", " + overrideableByRestore + ")");
}
return mutateSecureSetting(name, value, tag, makeDefault, requestingUserId,
MUTATION_OPERATION_INSERT, forceNotify, 0, overrideableByRestore);
@@ -1946,7 +1946,7 @@ public class SettingsProvider extends ContentProvider {
boolean overrideableByRestore) {
if (DEBUG) {
Slog.v(LOG_TAG, "insertSystemSetting(" + name + ", " + value + ", "
- + requestingUserId + ")");
+ + requestingUserId + ", " + overrideableByRestore + ")");
}
return mutateSystemSetting(name, value, /* tag= */ null, requestingUserId,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
index 17ebf6fc3235..0484defeb4d7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
@@ -30,6 +30,7 @@ import android.os.ShellCommand;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.util.Slog;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -94,6 +95,8 @@ final public class SettingsService extends Binder {
}
final static class MyShellCommand extends ShellCommand {
+ private static final String LOG_TAG = "SettingsShellCmd";
+
final SettingsProvider mProvider;
final boolean mDumping;
@@ -115,6 +118,7 @@ final public class SettingsService extends Binder {
String mTag = null;
int mResetMode = -1;
boolean mMakeDefault;
+ boolean mOverrideableByRestore;
MyShellCommand(SettingsProvider provider, boolean dumping) {
mProvider = provider;
@@ -209,6 +213,7 @@ final public class SettingsService extends Binder {
return -1;
}
break;
+ // At this point, mVerb == PUT
} else if (mKey == null) {
mKey = arg;
// keep going; there's another PUT arg
@@ -217,36 +222,8 @@ final public class SettingsService extends Binder {
// what we have so far is a valid command
valid = true;
// keep going; there may be another PUT arg
- } else if (mTag == null) {
- mTag = arg;
- if ("default".equalsIgnoreCase(mTag)) {
- mTag = null;
- mMakeDefault = true;
- if (peekNextArg() == null) {
- valid = true;
- } else {
- perr.println("Too many arguments");
- return -1;
- }
- break;
- }
- if (peekNextArg() == null) {
- valid = true;
- break;
- }
- } else { // PUT, final arg
- if (!"default".equalsIgnoreCase(arg)) {
- perr.println("Argument expected to be 'default'");
- return -1;
- }
- mMakeDefault = true;
- if (peekNextArg() == null) {
- valid = true;
- } else {
- perr.println("Too many arguments");
- return -1;
- }
- break;
+ } else {
+ valid = parseOptionalPutArgument(arg);
}
} while ((arg = getNextArg()) != null);
@@ -275,7 +252,8 @@ final public class SettingsService extends Binder {
pout.println(getForUser(iprovider, mUser, mTable, mKey));
break;
case PUT:
- putForUser(iprovider, mUser, mTable, mKey, mValue, mTag, mMakeDefault);
+ putForUser(iprovider, mUser, mTable, mKey, mValue, mTag, mMakeDefault,
+ mOverrideableByRestore);
break;
case DELETE:
pout.println("Deleted "
@@ -297,6 +275,41 @@ final public class SettingsService extends Binder {
return 0;
}
+ private boolean parseOptionalPutArgument(String arg) {
+ boolean valid = true;
+ // Given that the order is TAG default overrideableByRestore, we need to parse from the
+ // opposite direction
+ switch (arg) {
+ case "overrideableByRestore":
+ if (mOverrideableByRestore) {
+ valid = false;
+ } else {
+ mOverrideableByRestore = true;
+ }
+ break;
+ case "default":
+ if (mMakeDefault || mOverrideableByRestore) {
+ valid = false;
+ } else {
+ mMakeDefault = true;
+ }
+ break;
+ default: // tag
+ if (mMakeDefault || mOverrideableByRestore || mTag != null) {
+ valid = false;
+ } else {
+ mTag = arg;
+ }
+ break;
+ }
+ if (!valid) {
+ Slog.e(LOG_TAG, "parseOptionalPutArgument(" + arg + "): invalid state ("
+ + "mTag=" + mTag + ", mMakeDefault=" + mMakeDefault
+ + ", mOverrideableByRestore=" + mOverrideableByRestore + ")");
+ }
+ return valid;
+ }
+
List<String> listForUser(IContentProvider provider, int userHandle, String table) {
final String callListCommand;
if ("system".equals(table)) callListCommand = Settings.CALL_METHOD_LIST_SYSTEM;
@@ -351,7 +364,11 @@ final public class SettingsService extends Binder {
}
void putForUser(IContentProvider provider, int userHandle, final String table,
- final String key, final String value, String tag, boolean makeDefault) {
+ final String key, final String value, String tag, boolean makeDefault,
+ boolean overrideableByRestore) {
+ Slog.v(LOG_TAG, "putForUser(userId=" + userHandle + ", table=" + table + ", key=" + key
+ + ", value=" + value + ", tag=" + tag + ", makeDefault=" + makeDefault
+ + ", overrideableByRestore=" + overrideableByRestore + ")");
final String callPutCommand;
if ("system".equals(table)) {
callPutCommand = Settings.CALL_METHOD_PUT_SYSTEM;
@@ -377,6 +394,9 @@ final public class SettingsService extends Binder {
if (makeDefault) {
arg.putBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY, true);
}
+ if (overrideableByRestore) {
+ arg.putBoolean(Settings.CALL_METHOD_OVERRIDEABLE_BY_RESTORE_KEY, true);
+ }
final AttributionSource attributionSource = new AttributionSource(
Binder.getCallingUid(), resolveCallingPackage(), /*attributionTag*/ null);
provider.call(attributionSource, Settings.AUTHORITY,
@@ -474,10 +494,11 @@ final public class SettingsService extends Binder {
pw.println(" Print this help text.");
pw.println(" get [--user <USER_ID> | current] NAMESPACE KEY");
pw.println(" Retrieve the current value of KEY.");
- pw.println(" put [--user <USER_ID> | current] NAMESPACE KEY VALUE [TAG] [default]");
+ pw.println(" put [--user <USER_ID> | current] NAMESPACE KEY VALUE [TAG] [default] [overrideableByRestore]");
pw.println(" Change the contents of KEY to VALUE.");
- pw.println(" TAG to associate with the setting.");
+ pw.println(" TAG to associate with the setting (cannot be default or overrideableByRestore).");
pw.println(" {default} to set as the default, case-insensitive only for global/secure namespace");
+ pw.println(" {overrideableByRestore} to let the value be overridden by BackupManager on restore operations");
pw.println(" delete [--user <USER_ID> | current] NAMESPACE KEY");
pw.println(" Delete the entry for KEY.");
pw.println(" reset [--user <USER_ID> | current] NAMESPACE {PACKAGE_NAME | RESET_MODE}");
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
index 02de78bc84ce..30623acbbd31 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -149,9 +149,6 @@ fun ContentScope.CollapsedShadeHeader(
}
}
- val longerDateText by viewModel.longerDateText.collectAsStateWithLifecycle()
- val shorterDateText by viewModel.shorterDateText.collectAsStateWithLifecycle()
-
val isShadeLayoutWide = viewModel.isShadeLayoutWide
val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle()
@@ -167,8 +164,8 @@ fun ContentScope.CollapsedShadeHeader(
) {
Clock(scale = 1f, onClick = viewModel::onClockClicked)
VariableDayDate(
- longerDateText = longerDateText,
- shorterDateText = shorterDateText,
+ longerDateText = viewModel.longerDateText,
+ shorterDateText = viewModel.shorterDateText,
chipHighlight = viewModel.notificationsChipHighlight,
modifier = Modifier.element(ShadeHeader.Elements.CollapsedContentStart),
)
@@ -229,8 +226,6 @@ fun ContentScope.ExpandedShadeHeader(
derivedStateOf { shouldUseExpandedFormat(layoutState.transitionState) }
}
- val longerDateText by viewModel.longerDateText.collectAsStateWithLifecycle()
- val shorterDateText by viewModel.shorterDateText.collectAsStateWithLifecycle()
val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle()
Box(modifier = modifier.sysuiResTag(ShadeHeader.TestTags.Root)) {
@@ -269,8 +264,8 @@ fun ContentScope.ExpandedShadeHeader(
modifier = Modifier.element(ShadeHeader.Elements.ExpandedContent),
) {
VariableDayDate(
- longerDateText = longerDateText,
- shorterDateText = shorterDateText,
+ longerDateText = viewModel.longerDateText,
+ shorterDateText = viewModel.shorterDateText,
chipHighlight = viewModel.notificationsChipHighlight,
modifier = Modifier.widthIn(max = 90.dp),
)
@@ -337,12 +332,9 @@ fun ContentScope.OverlayShadeHeader(
modifier = Modifier.width(IntrinsicSize.Min).height(20.dp),
)
} else {
- val longerDateText by viewModel.longerDateText.collectAsStateWithLifecycle()
- val shorterDateText by
- viewModel.shorterDateText.collectAsStateWithLifecycle()
VariableDayDate(
- longerDateText = longerDateText,
- shorterDateText = shorterDateText,
+ longerDateText = viewModel.longerDateText,
+ shorterDateText = viewModel.shorterDateText,
chipHighlight = viewModel.notificationsChipHighlight,
)
}
@@ -546,11 +538,8 @@ private fun BatteryIcon(
@Composable
private fun ShadeCarrierGroup(viewModel: ShadeHeaderViewModel, modifier: Modifier = Modifier) {
- Row(modifier = modifier) {
- val subIds by viewModel.mobileSubIds.collectAsStateWithLifecycle()
-
- for (subId in subIds) {
- Spacer(modifier = Modifier.width(5.dp))
+ Row(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(5.dp)) {
+ for (subId in viewModel.mobileSubIds) {
AndroidView(
factory = { context ->
ModernShadeCarrierGroupMobileView.constructAndBind(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 50762edc1179..88c9e74551fd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -21,6 +21,7 @@ import android.content.res.Configuration
import android.hardware.biometrics.BiometricAuthenticator
import android.hardware.biometrics.BiometricConstants
import android.hardware.biometrics.BiometricManager
+import android.hardware.biometrics.BiometricPrompt
import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton
import android.hardware.biometrics.PromptInfo
import android.hardware.biometrics.PromptVerticalListContentView
@@ -290,7 +291,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
verify(callback)
.onDismissed(
- eq(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED),
+ eq(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L),
)
@@ -310,7 +311,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
)
verify(callback)
.onDismissed(
- eq(AuthDialogCallback.DISMISSED_USER_CANCELED),
+ eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L),
)
@@ -325,7 +326,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
verify(callback)
.onDismissed(
- eq(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE),
+ eq(BiometricPrompt.DISMISSED_REASON_NEGATIVE),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L),
)
@@ -352,7 +353,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
verify(callback)
.onDismissed(
- eq(AuthDialogCallback.DISMISSED_ERROR),
+ eq(BiometricPrompt.DISMISSED_REASON_ERROR),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L),
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
index acc97a9f8642..a1a2aa70d869 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -138,9 +138,9 @@ public class AuthControllerTest extends SysuiTestCase {
@Mock
private IBiometricContextListener mContextListener;
@Mock
- private AuthDialog mDialog1;
+ private AuthContainerView mDialog1;
@Mock
- private AuthDialog mDialog2;
+ private AuthContainerView mDialog2;
@Mock
private CommandQueue mCommandQueue;
@Mock
@@ -382,7 +382,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testSendsReasonUserCanceled_whenDismissedByUserCancel() throws Exception {
showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL,
null, /* credentialAttestation */
mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
@@ -393,7 +393,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testSendsReasonNegative_whenDismissedByButtonNegative() throws Exception {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE,
null, /* credentialAttestation */
mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
@@ -404,7 +404,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testSendsReasonConfirmed_whenDismissedByButtonPositive() throws Exception {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED,
null, /* credentialAttestation */
mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
@@ -415,7 +415,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testSendsReasonConfirmNotRequired_whenDismissedByAuthenticated() throws Exception {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED,
null, /* credentialAttestation */
mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
@@ -426,7 +426,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testSendsReasonError_whenDismissedByError() throws Exception {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_ERROR,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_ERROR,
null, /* credentialAttestation */
mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
@@ -437,7 +437,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testSendsReasonServerRequested_whenDismissedByServer() throws Exception {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BY_SYSTEM_SERVER,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED,
null, /* credentialAttestation */
mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
@@ -452,7 +452,7 @@ public class AuthControllerTest extends SysuiTestCase {
final byte[] credentialAttestation = generateRandomHAT();
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED,
credentialAttestation, mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
eq(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED),
@@ -462,7 +462,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testSendsReasonContentViewMoreOptions_whenButtonPressed() throws Exception {
showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS,
null, /* credentialAttestation */
mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
@@ -696,7 +696,7 @@ public class AuthControllerTest extends SysuiTestCase {
final byte[] credentialAttestation = generateRandomHAT();
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED,
credentialAttestation, mAuthController.mCurrentDialog.getRequestId());
verify(mReceiver).onDialogDismissed(
eq(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED),
@@ -755,7 +755,7 @@ public class AuthControllerTest extends SysuiTestCase {
public void testDoesNotCrash_whenTryAgainPressedAfterDismissal() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final long requestID = mAuthController.mCurrentDialog.getRequestId();
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL,
null, /* credentialAttestation */requestID);
mAuthController.onTryAgainPressed(requestID);
}
@@ -764,7 +764,7 @@ public class AuthControllerTest extends SysuiTestCase {
public void testDoesNotCrash_whenDeviceCredentialPressedAfterDismissal() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final long requestID = mAuthController.mCurrentDialog.getRequestId();
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL,
null /* credentialAttestation */, requestID);
mAuthController.onDeviceCredentialPressed(requestID);
}
@@ -818,7 +818,7 @@ public class AuthControllerTest extends SysuiTestCase {
// WHEN dialog is shown and then dismissed
showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
+ mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL,
null /* credentialAttestation */,
mAuthController.mCurrentDialog.getRequestId());
@@ -1218,14 +1218,14 @@ public class AuthControllerTest extends SysuiTestCase {
}
@Override
- protected AuthDialog buildDialog(DelayableExecutor bgExecutor, PromptInfo promptInfo,
+ protected AuthContainerView buildDialog(DelayableExecutor bgExecutor, PromptInfo promptInfo,
boolean requireConfirmation, int userId, int[] sensorIds,
String opPackageName, boolean skipIntro, long operationId, long requestId,
WakefulnessLifecycle wakefulnessLifecycle,
UserManager userManager,
LockPatternUtils lockPatternUtils, PromptViewModel viewModel) {
- AuthDialog dialog;
+ AuthContainerView dialog;
if (mBuildCount == 0) {
dialog = mDialog1;
} else if (mBuildCount == 1) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModelTest.kt
new file mode 100644
index 000000000000..052dfd52887f
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModelTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2025 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.kosmos.collectValues
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DozingToDreamingTransitionViewModelTest : SysuiTestCase() {
+ val kosmos = testKosmos()
+
+ val underTest by lazy { kosmos.dozingToDreamingTransitionViewModel }
+
+ @Test
+ fun notificationShadeAlpha() =
+ kosmos.runTest {
+ val values by collectValues(underTest.notificationAlpha)
+ assertThat(values).isEmpty()
+
+ fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.DOZING,
+ to = KeyguardState.DREAMING,
+ testScope,
+ )
+
+ assertThat(values).isNotEmpty()
+ values.forEach { assertThat(it).isEqualTo(0) }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorTest.kt
index 84fc93008f49..a3dd67f85150 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorTest.kt
@@ -22,6 +22,9 @@ import android.provider.AlarmClock
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.activityStarter
import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback
@@ -31,22 +34,32 @@ import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argThat
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import java.util.Date
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.milliseconds
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatcher
-import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class ShadeHeaderClockInteractorTest : SysuiTestCase() {
+
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val activityStarter = kosmos.activityStarter
private val nextAlarmController = kosmos.nextAlarmController
- val underTest = kosmos.shadeHeaderClockInteractor
+ private val underTest = kosmos.shadeHeaderClockInteractor
@Test
fun launchClockActivity_default() =
@@ -55,7 +68,7 @@ class ShadeHeaderClockInteractorTest : SysuiTestCase() {
verify(activityStarter)
.postStartActivityDismissingKeyguard(
argThat(IntentMatcherAction(AlarmClock.ACTION_SHOW_ALARMS)),
- any()
+ any(),
)
}
@@ -71,6 +84,75 @@ class ShadeHeaderClockInteractorTest : SysuiTestCase() {
underTest.launchClockActivity()
verify(activityStarter).postStartActivityDismissingKeyguard(any())
}
+
+ @Test
+ fun onTimezoneOrLocaleChanged_localeAndTimezoneChanged_emitsForEach() =
+ testScope.runTest {
+ val timeZoneOrLocaleChanges by collectValues(underTest.onTimezoneOrLocaleChanged)
+
+ sendIntentActionBroadcast(Intent.ACTION_TIMEZONE_CHANGED)
+ sendIntentActionBroadcast(Intent.ACTION_LOCALE_CHANGED)
+ sendIntentActionBroadcast(Intent.ACTION_LOCALE_CHANGED)
+ sendIntentActionBroadcast(Intent.ACTION_TIMEZONE_CHANGED)
+
+ assertThat(timeZoneOrLocaleChanges).hasSize(4)
+ }
+
+ @Test
+ fun onTimezoneOrLocaleChanged_timeChanged_doesNotEmit() =
+ testScope.runTest {
+ val timeZoneOrLocaleChanges by collectValues(underTest.onTimezoneOrLocaleChanged)
+ assertThat(timeZoneOrLocaleChanges).hasSize(1)
+
+ sendIntentActionBroadcast(Intent.ACTION_TIME_CHANGED)
+ sendIntentActionBroadcast(Intent.ACTION_TIME_TICK)
+
+ // Expect only 1 event to have been emitted onStart, but no more.
+ assertThat(timeZoneOrLocaleChanges).hasSize(1)
+ }
+
+ @Test
+ fun currentTime_timeChanged() =
+ testScope.runTest {
+ val currentTime by collectLastValue(underTest.currentTime)
+
+ sendIntentActionBroadcast(Intent.ACTION_TIME_CHANGED)
+ val earlierTime = checkNotNull(currentTime)
+
+ advanceTimeBy(3.seconds)
+ runCurrent()
+
+ sendIntentActionBroadcast(Intent.ACTION_TIME_CHANGED)
+ val laterTime = checkNotNull(currentTime)
+
+ assertThat(differenceBetween(laterTime, earlierTime)).isEqualTo(3.seconds)
+ }
+
+ @Test
+ fun currentTime_timeTicked() =
+ testScope.runTest {
+ val currentTime by collectLastValue(underTest.currentTime)
+
+ sendIntentActionBroadcast(Intent.ACTION_TIME_TICK)
+ val earlierTime = checkNotNull(currentTime)
+
+ advanceTimeBy(7.seconds)
+ runCurrent()
+
+ sendIntentActionBroadcast(Intent.ACTION_TIME_TICK)
+ val laterTime = checkNotNull(currentTime)
+
+ assertThat(differenceBetween(laterTime, earlierTime)).isEqualTo(7.seconds)
+ }
+
+ private fun differenceBetween(date1: Date, date2: Date): Duration {
+ return (date1.time - date2.time).milliseconds
+ }
+
+ private fun TestScope.sendIntentActionBroadcast(intentAction: String) {
+ kosmos.broadcastDispatcher.sendIntentToMatchingReceiversOnly(context, Intent(intentAction))
+ runCurrent()
+ }
}
private class IntentMatcherAction(private val action: String) : ArgumentMatcher<Intent> {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
index 061e04ef29f7..37b4688f753d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
@@ -25,12 +25,15 @@ import com.android.systemui.shade.domain.interactor.disableDualShade
import com.android.systemui.shade.domain.interactor.enableDualShade
import com.android.systemui.shade.domain.interactor.enableSingleShade
import com.android.systemui.shade.domain.interactor.enableSplitShade
+import com.android.systemui.shade.domain.interactor.shadeMode
+import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel.HeaderChipHighlight
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.fakeMobileIconsInteractor
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.argThat
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -43,6 +46,7 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
@EnableSceneContainer
@@ -64,14 +68,15 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
@Test
fun mobileSubIds_update() =
testScope.runTest {
- val mobileSubIds by collectLastValue(underTest.mobileSubIds)
mobileIconsInteractor.filteredSubscriptions.value = listOf(SUB_1)
+ runCurrent()
- assertThat(mobileSubIds).isEqualTo(listOf(1))
+ assertThat(underTest.mobileSubIds).isEqualTo(listOf(1))
mobileIconsInteractor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+ runCurrent()
- assertThat(mobileSubIds).isEqualTo(listOf(1, 2))
+ assertThat(underTest.mobileSubIds).isEqualTo(listOf(1, 2))
}
@Test
@@ -116,13 +121,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
@Test
fun onSystemIconChipClicked_lockedOnQsShade_collapsesShadeToLockscreen() =
testScope.runTest {
- kosmos.enableDualShade()
+ setupDualShadeState(scene = Scenes.Lockscreen, overlay = Overlays.QuickSettingsShade)
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
- setDeviceEntered(false)
- setScene(Scenes.Lockscreen)
- setOverlay(Overlays.QuickSettingsShade)
- assertThat(currentOverlays).isNotEmpty()
underTest.onSystemIconChipClicked()
runCurrent()
@@ -134,13 +135,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
@Test
fun onSystemIconChipClicked_lockedOnNotifShade_expandsQsShade() =
testScope.runTest {
- kosmos.enableDualShade()
+ setupDualShadeState(scene = Scenes.Lockscreen, overlay = Overlays.NotificationsShade)
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
- setDeviceEntered(false)
- setScene(Scenes.Lockscreen)
- setOverlay(Overlays.NotificationsShade)
- assertThat(currentOverlays).isNotEmpty()
underTest.onSystemIconChipClicked()
runCurrent()
@@ -166,13 +163,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
@Test
fun onSystemIconChipClicked_unlockedOnQsShade_collapsesShadeToGone() =
testScope.runTest {
- kosmos.enableDualShade()
+ setupDualShadeState(scene = Scenes.Gone, overlay = Overlays.QuickSettingsShade)
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
- setDeviceEntered(true)
- setScene(Scenes.Gone)
- setOverlay(Overlays.QuickSettingsShade)
- assertThat(currentOverlays).isNotEmpty()
underTest.onSystemIconChipClicked()
runCurrent()
@@ -184,13 +177,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
@Test
fun onSystemIconChipClicked_unlockedOnNotifShade_expandsQsShade() =
testScope.runTest {
- kosmos.enableDualShade()
+ setupDualShadeState(scene = Scenes.Gone, overlay = Overlays.NotificationsShade)
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
- setDeviceEntered(true)
- setScene(Scenes.Gone)
- setOverlay(Overlays.NotificationsShade)
- assertThat(currentOverlays).isNotEmpty()
underTest.onSystemIconChipClicked()
runCurrent()
@@ -203,13 +192,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
@Test
fun onNotificationIconChipClicked_lockedOnNotifShade_collapsesShadeToLockscreen() =
testScope.runTest {
- kosmos.enableDualShade()
+ setupDualShadeState(scene = Scenes.Lockscreen, overlay = Overlays.NotificationsShade)
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
- setDeviceEntered(false)
- setScene(Scenes.Lockscreen)
- setOverlay(Overlays.NotificationsShade)
- assertThat(currentOverlays).isNotEmpty()
underTest.onNotificationIconChipClicked()
runCurrent()
@@ -221,13 +206,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
@Test
fun onNotificationIconChipClicked_lockedOnQsShade_expandsNotifShade() =
testScope.runTest {
- kosmos.enableDualShade()
+ setupDualShadeState(scene = Scenes.Lockscreen, overlay = Overlays.QuickSettingsShade)
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
- setDeviceEntered(false)
- setScene(Scenes.Lockscreen)
- setOverlay(Overlays.QuickSettingsShade)
- assertThat(currentOverlays).isNotEmpty()
underTest.onNotificationIconChipClicked()
runCurrent()
@@ -240,13 +221,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
@Test
fun onNotificationIconChipClicked_unlockedOnNotifShade_collapsesShadeToGone() =
testScope.runTest {
- kosmos.enableDualShade()
+ setupDualShadeState(scene = Scenes.Gone, overlay = Overlays.NotificationsShade)
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
- setDeviceEntered(true)
- setScene(Scenes.Gone)
- setOverlay(Overlays.NotificationsShade)
- assertThat(currentOverlays).isNotEmpty()
underTest.onNotificationIconChipClicked()
runCurrent()
@@ -258,13 +235,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
@Test
fun onNotificationIconChipClicked_unlockedOnQsShade_expandsNotifShade() =
testScope.runTest {
- kosmos.enableDualShade()
+ setupDualShadeState(scene = Scenes.Gone, overlay = Overlays.QuickSettingsShade)
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
- setDeviceEntered(true)
- setScene(Scenes.Gone)
- setOverlay(Overlays.QuickSettingsShade)
- assertThat(currentOverlays).isNotEmpty()
underTest.onNotificationIconChipClicked()
runCurrent()
@@ -319,22 +292,13 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
@Test
fun highlightChips_notifsOpenInDualShade_notifsStrongQuickSettingsWeak() =
testScope.runTest {
- kosmos.enableDualShade()
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
-
// Test the lockscreen scenario.
- setScene(Scenes.Lockscreen)
- setOverlay(Overlays.NotificationsShade)
+ setupDualShadeState(scene = Scenes.Lockscreen, overlay = Overlays.NotificationsShade)
assertThat(underTest.notificationsChipHighlight).isEqualTo(HeaderChipHighlight.Strong)
assertThat(underTest.quickSettingsChipHighlight).isEqualTo(HeaderChipHighlight.Weak)
// Test the unlocked scenario.
- setDeviceEntered(true)
- setScene(Scenes.Gone)
- setOverlay(Overlays.NotificationsShade)
- assertThat(currentScene).isEqualTo(Scenes.Gone)
- assertThat(currentOverlays).isNotEmpty()
+ setupDualShadeState(scene = Scenes.Gone, overlay = Overlays.NotificationsShade)
assertThat(underTest.notificationsChipHighlight).isEqualTo(HeaderChipHighlight.Strong)
assertThat(underTest.quickSettingsChipHighlight).isEqualTo(HeaderChipHighlight.Weak)
}
@@ -342,22 +306,13 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
@Test
fun highlightChips_quickSettingsOpenInDualShade_notifsWeakQuickSettingsStrong() =
testScope.runTest {
- kosmos.enableDualShade()
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
-
// Test the lockscreen scenario.
- setScene(Scenes.Lockscreen)
- setOverlay(Overlays.QuickSettingsShade)
+ setupDualShadeState(scene = Scenes.Lockscreen, overlay = Overlays.QuickSettingsShade)
assertThat(underTest.notificationsChipHighlight).isEqualTo(HeaderChipHighlight.Weak)
assertThat(underTest.quickSettingsChipHighlight).isEqualTo(HeaderChipHighlight.Strong)
// Test the unlocked scenario.
- setDeviceEntered(true)
- setScene(Scenes.Gone)
- setOverlay(Overlays.QuickSettingsShade)
- assertThat(currentScene).isEqualTo(Scenes.Gone)
- assertThat(currentOverlays).isNotEmpty()
+ setupDualShadeState(scene = Scenes.Gone, overlay = Overlays.QuickSettingsShade)
assertThat(underTest.notificationsChipHighlight).isEqualTo(HeaderChipHighlight.Weak)
assertThat(underTest.quickSettingsChipHighlight).isEqualTo(HeaderChipHighlight.Strong)
}
@@ -365,21 +320,13 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
@Test
fun highlightChips_noOverlaysInDualShade_bothNone() =
testScope.runTest {
- kosmos.enableDualShade()
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
-
// Test the lockscreen scenario.
- setScene(Scenes.Lockscreen)
- assertThat(currentOverlays).isEmpty()
+ setupDualShadeState(scene = Scenes.Lockscreen)
assertThat(underTest.notificationsChipHighlight).isEqualTo(HeaderChipHighlight.None)
assertThat(underTest.quickSettingsChipHighlight).isEqualTo(HeaderChipHighlight.None)
// Test the unlocked scenario.
- setDeviceEntered(true)
- setScene(Scenes.Gone)
- assertThat(currentScene).isEqualTo(Scenes.Gone)
- assertThat(currentOverlays).isEmpty()
+ setupDualShadeState(scene = Scenes.Gone)
assertThat(underTest.notificationsChipHighlight).isEqualTo(HeaderChipHighlight.None)
assertThat(underTest.quickSettingsChipHighlight).isEqualTo(HeaderChipHighlight.None)
}
@@ -401,21 +348,43 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
)
}
- private fun setScene(key: SceneKey) {
- sceneInteractor.changeScene(key, "test")
+ private fun TestScope.setupDualShadeState(scene: SceneKey, overlay: OverlayKey? = null) {
+ kosmos.enableDualShade()
+ val shadeMode by collectLastValue(kosmos.shadeMode)
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ if (scene == Scenes.Gone) {
+ // Unlock the device, marking the device has been entered.
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+ }
+ runCurrent()
+ assertThat(shadeMode).isEqualTo(ShadeMode.Dual)
+
+ sceneInteractor.changeScene(scene, "test")
+ checkNotNull(currentOverlays).forEach { sceneInteractor.instantlyHideOverlay(it, "test") }
+ runCurrent()
+ overlay?.let { sceneInteractor.showOverlay(it, "test") }
sceneInteractor.setTransitionState(
- MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key))
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(scene, setOfNotNull(overlay))
+ )
)
- testScope.runCurrent()
+ runCurrent()
+
+ assertThat(currentScene).isEqualTo(scene)
+ if (overlay == null) {
+ assertThat(currentOverlays).isEmpty()
+ } else {
+ assertThat(currentOverlays).containsExactly(overlay)
+ }
}
- private fun setOverlay(key: OverlayKey) {
- val currentOverlays = sceneInteractor.currentOverlays.value + key
- sceneInteractor.showOverlay(key, "test")
+ private fun setScene(key: SceneKey) {
+ sceneInteractor.changeScene(key, "test")
sceneInteractor.setTransitionState(
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Idle(sceneInteractor.currentScene.value, currentOverlays)
- )
+ MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key))
)
testScope.runCurrent()
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index b6537118324e..4c8a8f1c13d7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -33,6 +33,7 @@ import android.graphics.PixelFormat;
import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager.Authenticators;
+import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.PromptInfo;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -100,7 +101,7 @@ import javax.inject.Provider;
*/
@Deprecated
public class AuthContainerView extends LinearLayout
- implements AuthDialog, WakefulnessLifecycle.Observer, CredentialView.Host {
+ implements WakefulnessLifecycle.Observer, CredentialView.Host {
private static final String TAG = "AuthContainerView";
@@ -158,12 +159,11 @@ public class AuthContainerView extends LinearLayout
private final Set<Integer> mFailedModalities = new HashSet<Integer>();
private final OnBackInvokedCallback mBackCallback = this::onBackInvoked;
- private final @Background DelayableExecutor mBackgroundExecutor;
private final MSDLPlayer mMSDLPlayer;
// Non-null only if the dialog is in the act of dismissing and has not sent the reason yet.
- @Nullable @AuthDialogCallback.DismissedReason private Integer mPendingCallbackReason;
+ @Nullable @BiometricPrompt.DismissedReason private Integer mPendingCallbackReason;
// HAT received from LockSettingsService when credential is verified.
@Nullable private byte[] mCredentialAttestation;
@@ -188,18 +188,18 @@ public class AuthContainerView extends LinearLayout
final class BiometricCallback implements Spaghetti.Callback {
@Override
public void onAuthenticated() {
- animateAway(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED);
+ animateAway(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED);
}
@Override
public void onUserCanceled() {
sendEarlyUserCanceled();
- animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
+ animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
}
@Override
public void onButtonNegative() {
- animateAway(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE);
+ animateAway(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
}
@Override
@@ -210,12 +210,12 @@ public class AuthContainerView extends LinearLayout
@Override
public void onContentViewMoreOptionsButtonPressed() {
- animateAway(AuthDialogCallback.DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS);
+ animateAway(BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS);
}
@Override
public void onError() {
- animateAway(AuthDialogCallback.DISMISSED_ERROR);
+ animateAway(BiometricPrompt.DISMISSED_REASON_ERROR);
}
@Override
@@ -234,20 +234,20 @@ public class AuthContainerView extends LinearLayout
@Override
public void onAuthenticatedAndConfirmed() {
- animateAway(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE);
+ animateAway(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED);
}
}
@Override
public void onCredentialMatched(@NonNull byte[] attestation) {
mCredentialAttestation = attestation;
- animateAway(AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED);
+ animateAway(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED);
}
@Override
public void onCredentialAborted() {
sendEarlyUserCanceled();
- animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
+ animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
}
@Override
@@ -277,7 +277,7 @@ public class AuthContainerView extends LinearLayout
com.android.settingslib.R.string.failed_attempts_now_wiping_dialog_dismiss,
null /* OnClickListener */)
.setOnDismissListener(
- dialog -> animateAway(AuthDialogCallback.DISMISSED_ERROR))
+ dialog -> animateAway(BiometricPrompt.DISMISSED_REASON_ERROR))
.create();
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
alertDialog.show();
@@ -349,7 +349,6 @@ public class AuthContainerView extends LinearLayout
mPanelView = mLayout.findViewById(R.id.panel);
mPanelController = new AuthPanelController(mContext, mPanelView);
- mBackgroundExecutor = bgExecutor;
mInteractionJankMonitor = jankMonitor;
mCredentialViewModelProvider = credentialViewModelProvider;
@@ -394,7 +393,7 @@ public class AuthContainerView extends LinearLayout
@VisibleForTesting
public void onBackInvoked() {
sendEarlyUserCanceled();
- animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
+ animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
}
void sendEarlyUserCanceled() {
@@ -402,7 +401,6 @@ public class AuthContainerView extends LinearLayout
BiometricConstants.BIOMETRIC_SYSTEM_EVENT_EARLY_USER_CANCEL, getRequestId());
}
- @Override
public boolean isAllowDeviceCredentials() {
return Utils.isDeviceCredentialAllowed(mConfig.mPromptInfo);
}
@@ -450,7 +448,6 @@ public class AuthContainerView extends LinearLayout
mPanelController.setContainerDimensions(getMeasuredWidth(), getMeasuredHeight());
}
- @Override
public void onOrientationChanged() {
}
@@ -538,10 +535,9 @@ public class AuthContainerView extends LinearLayout
@Override
public void onStartedGoingToSleep() {
- animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
+ animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
}
- @Override
public void show(WindowManager wm) {
wm.addView(this, getLayoutParams(mWindowToken, mConfig.mPromptInfo.getTitle()));
}
@@ -559,7 +555,6 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public void dismissWithoutCallback(boolean animate) {
if (animate) {
animateAway(false /* sendReason */, 0 /* reason */);
@@ -569,12 +564,10 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public void dismissFromSystemServer() {
animateAway(false /* sendReason */, 0 /* reason */);
}
- @Override
public void onAuthenticationSucceeded(@Modality int modality) {
if (mBiometricView != null) {
mBiometricView.onAuthenticationSucceeded(modality);
@@ -583,7 +576,6 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public void onAuthenticationFailed(@Modality int modality, String failureReason) {
if (mBiometricView != null) {
mFailedModalities.add(modality);
@@ -593,7 +585,6 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public void onHelp(@Modality int modality, String help) {
if (mBiometricView != null) {
mBiometricView.onHelp(modality, help);
@@ -602,7 +593,6 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public void onError(@Modality int modality, String error) {
if (mBiometricView != null) {
mBiometricView.onError(modality, error);
@@ -611,7 +601,6 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public void onPointerDown() {
if (mBiometricView != null) {
if (mFailedModalities.contains(TYPE_FACE)) {
@@ -624,22 +613,18 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public String getOpPackageName() {
return mConfig.mOpPackageName;
}
- @Override
public String getClassNameIfItIsConfirmDeviceCredentialActivity() {
return mConfig.mPromptInfo.getClassNameIfItIsConfirmDeviceCredentialActivity();
}
- @Override
public long getRequestId() {
return mConfig.mRequestId;
}
- @Override
public void animateToCredentialUI(boolean isError) {
if (mBiometricView != null) {
mBiometricView.startTransitionToCredentialUI(isError);
@@ -648,11 +633,11 @@ public class AuthContainerView extends LinearLayout
}
}
- void animateAway(@AuthDialogCallback.DismissedReason int reason) {
+ void animateAway(@BiometricPrompt.DismissedReason int reason) {
animateAway(true /* sendReason */, reason);
}
- private void animateAway(boolean sendReason, @AuthDialogCallback.DismissedReason int reason) {
+ private void animateAway(boolean sendReason, @BiometricPrompt.DismissedReason int reason) {
if (mContainerState == STATE_ANIMATING_IN) {
Log.w(TAG, "startDismiss(): waiting for onDialogAnimatedIn");
mContainerState = STATE_PENDING_DISMISS;
@@ -732,7 +717,7 @@ public class AuthContainerView extends LinearLayout
private void onDialogAnimatedIn() {
if (mContainerState == STATE_PENDING_DISMISS) {
Log.d(TAG, "onDialogAnimatedIn(): mPendingDismissDialog=true, dismissing now");
- animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
+ animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
return;
}
if (mContainerState == STATE_ANIMATING_OUT || mContainerState == STATE_GONE) {
@@ -748,7 +733,6 @@ public class AuthContainerView extends LinearLayout
}
}
- @Override
public PromptViewModel getViewModel() {
return mPromptViewModel;
}
@@ -776,7 +760,6 @@ public class AuthContainerView extends LinearLayout
return lp;
}
- @Override
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.println(" isAttachedToWindow=" + isAttachedToWindow());
pw.println(" containerState=" + mContainerState);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index eee5f9e34317..68a282018ba4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -163,7 +163,7 @@ public class AuthController implements
// TODO: These should just be saved from onSaveState
private SomeArgs mCurrentDialogArgs;
@VisibleForTesting
- AuthDialog mCurrentDialog;
+ AuthContainerView mCurrentDialog;
@NonNull private final WindowManager mWindowManager;
@NonNull private final DisplayManager mDisplayManager;
@@ -222,7 +222,7 @@ public class AuthController implements
closeDialog(BiometricPrompt.DISMISSED_REASON_USER_CANCEL, reasonString);
}
- private void closeDialog(@DismissedReason int reason, String reasonString) {
+ private void closeDialog(@BiometricPrompt.DismissedReason int reason, String reasonString) {
if (isShowing()) {
Log.i(TAG, "Close BP, reason :" + reasonString);
mCurrentDialog.dismissWithoutCallback(true /* animate */);
@@ -511,60 +511,14 @@ public class AuthController implements
}
@Override
- public void onDismissed(@DismissedReason int reason,
- @Nullable byte[] credentialAttestation, long requestId) {
-
+ public void onDismissed(@BiometricPrompt.DismissedReason int reason,
+ @Nullable byte[] credentialAttestation, long requestId) {
if (mCurrentDialog != null && requestId != mCurrentDialog.getRequestId()) {
Log.w(TAG, "requestId doesn't match, skip onDismissed");
return;
}
- switch (reason) {
- case AuthDialogCallback.DISMISSED_USER_CANCELED:
- sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_USER_CANCEL,
- credentialAttestation);
- break;
-
- case AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE:
- sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_NEGATIVE,
- credentialAttestation);
- break;
-
- case AuthDialogCallback.DISMISSED_BUTTON_POSITIVE:
- sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED,
- credentialAttestation);
- break;
-
- case AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED:
- sendResultAndCleanUp(
- BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED,
- credentialAttestation);
- break;
-
- case AuthDialogCallback.DISMISSED_ERROR:
- sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_ERROR,
- credentialAttestation);
- break;
-
- case AuthDialogCallback.DISMISSED_BY_SYSTEM_SERVER:
- sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED,
- credentialAttestation);
- break;
-
- case AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED:
- sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED,
- credentialAttestation);
- break;
-
- case AuthDialogCallback.DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS:
- sendResultAndCleanUp(
- BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS,
- credentialAttestation);
- break;
- default:
- Log.e(TAG, "Unhandled reason: " + reason);
- break;
- }
+ sendResultAndCleanUp(reason, credentialAttestation);
}
@Override
@@ -699,7 +653,7 @@ public class AuthController implements
mUdfpsController.onAodInterrupt(screenX, screenY, major, minor);
}
- private void sendResultAndCleanUp(@DismissedReason int reason,
+ private void sendResultAndCleanUp(@BiometricPrompt.DismissedReason int reason,
@Nullable byte[] credentialAttestation) {
if (mReceiver == null) {
Log.e(TAG, "sendResultAndCleanUp: Receiver is null");
@@ -1244,7 +1198,7 @@ public class AuthController implements
final long requestId = args.argl2;
// Create a new dialog but do not replace the current one yet.
- final AuthDialog newDialog = buildDialog(
+ final AuthContainerView newDialog = buildDialog(
mBackgroundExecutor,
promptInfo,
requireConfirmation,
@@ -1327,7 +1281,7 @@ public class AuthController implements
return mContext.createDisplayContext(display).getSystemService(WindowManager.class);
}
- private void onDialogDismissed(@DismissedReason int reason) {
+ private void onDialogDismissed(@BiometricPrompt.DismissedReason int reason) {
if (DEBUG) Log.d(TAG, "onDialogDismissed: " + reason);
if (mCurrentDialog == null) {
Log.w(TAG, "Dialog already dismissed");
@@ -1361,7 +1315,7 @@ public class AuthController implements
}
}
- protected AuthDialog buildDialog(@Background DelayableExecutor bgExecutor,
+ protected AuthContainerView buildDialog(@Background DelayableExecutor bgExecutor,
PromptInfo promptInfo, boolean requireConfirmation, int userId, int[] sensorIds,
String opPackageName, boolean skipIntro, long operationId, long requestId,
@NonNull WakefulnessLifecycle wakefulnessLifecycle,
@@ -1389,7 +1343,7 @@ public class AuthController implements
@Override
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
- final AuthDialog dialog = mCurrentDialog;
+ final AuthContainerView dialog = mCurrentDialog;
pw.println(" mCachedDisplayInfo=" + mCachedDisplayInfo);
pw.println(" mScaleFactor=" + mScaleFactor);
pw.println(" fingerprintSensorLocationInNaturalOrientation="
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
deleted file mode 100644
index 861191671ba9..000000000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2019 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.hardware.biometrics.BiometricAuthenticator.Modality;
-import android.view.WindowManager;
-
-import com.android.systemui.Dumpable;
-import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
-
-/**
- * Interface for the biometric dialog UI.
- *
- * TODO(b/287311775): remove along with legacy controller once flag is removed
- */
-@Deprecated
-public interface AuthDialog extends Dumpable {
-
- /**
- * Parameters used when laying out {@link AuthBiometricView}, its subclasses, and
- * {@link AuthPanelController}.
- */
- class LayoutParams {
- public final int mMediumHeight;
- public final int mMediumWidth;
-
- public LayoutParams(int mediumWidth, int mediumHeight) {
- mMediumWidth = mediumWidth;
- mMediumHeight = mediumHeight;
- }
- }
-
- /**
- * Show the dialog.
- * @param wm
- */
- void show(WindowManager wm);
-
- /**
- * Dismiss the dialog without sending a callback.
- */
- void dismissWithoutCallback(boolean animate);
-
- /**
- * Dismiss the dialog. Animate away.
- */
- void dismissFromSystemServer();
-
- /**
- * Biometric authenticated. May be pending user confirmation, or completed.
- */
- void onAuthenticationSucceeded(@Modality int modality);
-
- /**
- * Authentication failed (reject, timeout). Dialog stays showing.
- * @param modality sensor modality that triggered the error
- * @param failureReason message
- */
- void onAuthenticationFailed(@Modality int modality, String failureReason);
-
- /**
- * Authentication rejected, or help message received.
- * @param modality sensor modality that triggered the help message
- * @param help message
- */
- void onHelp(@Modality int modality, String help);
-
- /**
- * Authentication failed. Dialog going away.
- * @param modality sensor modality that triggered the error
- * @param error message
- */
- void onError(@Modality int modality, String error);
-
- /** UDFPS pointer down event. */
- void onPointerDown();
-
- /**
- * Get the client's package name
- */
- String getOpPackageName();
-
- /**
- * Get the class name of ConfirmDeviceCredentialActivity. Returns null if the direct caller is
- * not ConfirmDeviceCredentialActivity.
- */
- String getClassNameIfItIsConfirmDeviceCredentialActivity();
-
- /** The requestId of the underlying operation within the framework. */
- long getRequestId();
-
- /**
- * Animate to credential UI. Typically called after biometric is locked out.
- */
- void animateToCredentialUI(boolean isError);
-
- /**
- * @return true if device credential is allowed.
- */
- boolean isAllowDeviceCredentials();
-
- /**
- * Called when the device's orientation changed and the dialog may need to do another
- * layout. This is most relevant to UDFPS since configuration changes are not sent by
- * the framework in equivalent cases (landscape to reverse landscape) but the dialog
- * must remain fixed on the physical sensor location.
- */
- void onOrientationChanged();
-
- PromptViewModel getViewModel();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
index 024c6eaa75bb..31c63d3c57e0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
@@ -16,40 +16,20 @@
package com.android.systemui.biometrics;
-import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.hardware.biometrics.BiometricPrompt;
/**
* Callback interface for dialog views. These should be implemented by the controller (e.g.
* FingerprintDialogImpl) and passed into their views (e.g. FingerprintDialogView).
*/
public interface AuthDialogCallback {
-
- int DISMISSED_USER_CANCELED = 1;
- int DISMISSED_BUTTON_NEGATIVE = 2;
- int DISMISSED_BUTTON_POSITIVE = 3;
- int DISMISSED_BIOMETRIC_AUTHENTICATED = 4;
- int DISMISSED_ERROR = 5;
- int DISMISSED_BY_SYSTEM_SERVER = 6;
- int DISMISSED_CREDENTIAL_AUTHENTICATED = 7;
- int DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS = 8;
-
- @IntDef({DISMISSED_USER_CANCELED,
- DISMISSED_BUTTON_NEGATIVE,
- DISMISSED_BUTTON_POSITIVE,
- DISMISSED_BIOMETRIC_AUTHENTICATED,
- DISMISSED_ERROR,
- DISMISSED_BY_SYSTEM_SERVER,
- DISMISSED_CREDENTIAL_AUTHENTICATED,
- DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS})
- @interface DismissedReason {}
-
/**
* Invoked when the dialog is dismissed
- * @param reason
+ * @param reason - the {@link BiometricPrompt.DismissedReason} for dismissing
* @param credentialAttestation the HAT received from LockSettingsService upon verification
*/
- void onDismissed(@DismissedReason int reason,
+ void onDismissed(@BiometricPrompt.DismissedReason int reason,
@Nullable byte[] credentialAttestation, long requestId);
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 6f5f662d6fa3..0700ec639153 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -159,6 +159,7 @@ constructor(
val isKeyguardOccludedLegacy = keyguardInteractor.isKeyguardOccluded.value
val primaryBouncerShowing = keyguardInteractor.primaryBouncerShowing.value
val isKeyguardGoingAway = keyguardInteractor.isKeyguardGoingAway.value
+ val canStartDreaming = dreamManager.canStartDreaming(false)
if (!deviceEntryInteractor.isLockscreenEnabled()) {
if (!SceneContainerFlag.isEnabled) {
@@ -191,6 +192,13 @@ constructor(
if (!SceneContainerFlag.isEnabled) {
transitionToGlanceableHub()
}
+ } else if (canStartDreaming) {
+ // If we're waking up to dream, transition directly to dreaming without
+ // showing the lockscreen.
+ startTransitionTo(
+ KeyguardState.DREAMING,
+ ownerReason = "moving from doze to dream",
+ )
} else {
startTransitionTo(KeyguardState.LOCKSCREEN)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt
index e6a85c6860c5..9018c58a7e36 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt
@@ -39,4 +39,6 @@ constructor(animationFlow: KeyguardTransitionAnimationFlow) {
)
val lockscreenAlpha: Flow<Float> = transitionAnimation.immediatelyTransitionTo(0f)
+ // Notifications should not be shown while transitioning to dream.
+ val notificationAlpha = transitionAnimation.immediatelyTransitionTo(0f)
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractor.kt
index 186bfcbbc8e2..a4de1d675a15 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractor.kt
@@ -17,11 +17,19 @@
package com.android.systemui.shade.domain.interactor
import android.content.Intent
+import android.content.IntentFilter
+import android.os.UserHandle
import android.provider.AlarmClock
+import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.shade.data.repository.ShadeHeaderClockRepository
+import com.android.systemui.util.kotlin.emitOnStart
+import com.android.systemui.util.time.SystemClock
+import java.util.Date
import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
@SysUISingleton
class ShadeHeaderClockInteractor
@@ -29,7 +37,20 @@ class ShadeHeaderClockInteractor
constructor(
private val repository: ShadeHeaderClockRepository,
private val activityStarter: ActivityStarter,
+ private val broadcastDispatcher: BroadcastDispatcher,
+ private val systemClock: SystemClock,
) {
+ /** [Flow] that emits `Unit` whenever the timezone or locale has changed. */
+ val onTimezoneOrLocaleChanged: Flow<Unit> =
+ broadcastFlowForActions(Intent.ACTION_TIMEZONE_CHANGED, Intent.ACTION_LOCALE_CHANGED)
+ .emitOnStart()
+
+ /** [Flow] that emits the current `Date` every minute, or when the system time has changed. */
+ val currentTime: Flow<Date> =
+ broadcastFlowForActions(Intent.ACTION_TIME_TICK, Intent.ACTION_TIME_CHANGED)
+ .emitOnStart()
+ .map { Date(systemClock.currentTimeMillis()) }
+
/** Launch the clock activity. */
fun launchClockActivity() {
val nextAlarmIntent = repository.nextAlarmIntent
@@ -38,8 +59,22 @@ constructor(
} else {
activityStarter.postStartActivityDismissingKeyguard(
Intent(AlarmClock.ACTION_SHOW_ALARMS),
- 0
+ 0,
)
}
}
+
+ /**
+ * Returns a `Flow` that, when collected, emits `Unit` whenever a broadcast matching one of the
+ * given [actionsToFilter] is received.
+ */
+ private fun broadcastFlowForActions(
+ vararg actionsToFilter: String,
+ user: UserHandle = UserHandle.SYSTEM,
+ ): Flow<Unit> {
+ return broadcastDispatcher.broadcastFlow(
+ filter = IntentFilter().apply { actionsToFilter.forEach(::addAction) },
+ user = user,
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
index 8c38d2e7550c..63161db7902b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
@@ -18,16 +18,13 @@ package com.android.systemui.shade.ui.viewmodel
import android.content.Context
import android.content.Intent
-import android.content.IntentFilter
import android.icu.text.DateFormat
import android.icu.text.DisplayContext
-import android.os.UserHandle
import android.provider.Settings
import android.view.ViewGroup
import androidx.compose.runtime.getValue
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.battery.BatteryMeterViewController
-import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.plugins.ActivityStarter
@@ -50,18 +47,18 @@ import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIc
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
-import java.util.Date
import java.util.Locale
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.mapLatest
/** Models UI state for the shade header. */
+@OptIn(ExperimentalCoroutinesApi::class)
class ShadeHeaderViewModel
@AssistedInject
constructor(
@@ -70,7 +67,7 @@ constructor(
private val sceneInteractor: SceneInteractor,
private val shadeInteractor: ShadeInteractor,
private val shadeModeInteractor: ShadeModeInteractor,
- private val mobileIconsInteractor: MobileIconsInteractor,
+ mobileIconsInteractor: MobileIconsInteractor,
val mobileIconsViewModel: MobileIconsViewModel,
private val privacyChipInteractor: PrivacyChipInteractor,
private val clockInteractor: ShadeHeaderClockInteractor,
@@ -78,8 +75,8 @@ constructor(
private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
val statusBarIconController: StatusBarIconController,
val notificationIconContainerStatusBarViewBinder: NotificationIconContainerStatusBarViewBinder,
- private val broadcastDispatcher: BroadcastDispatcher,
) : ExclusiveActivatable() {
+
private val hydrator = Hydrator("ShadeHeaderViewModel.hydrator")
val createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager =
@@ -127,9 +124,16 @@ constructor(
/** True if there is exactly one mobile connection. */
val isSingleCarrier: StateFlow<Boolean> = mobileIconsInteractor.isSingleCarrier
- private val _mobileSubIds = MutableStateFlow(emptyList<Int>())
/** The list of subscription Ids for current mobile connections. */
- val mobileSubIds: StateFlow<List<Int>> = _mobileSubIds.asStateFlow()
+ val mobileSubIds: List<Int> by
+ hydrator.hydratedStateOf(
+ traceName = "mobileSubIds",
+ initialValue = emptyList(),
+ source =
+ mobileIconsInteractor.filteredSubscriptions.map { list ->
+ list.map { it.subscriptionId }
+ },
+ )
/** The list of PrivacyItems to be displayed by the privacy chip. */
val privacyItems: StateFlow<List<PrivacyItem>> = privacyChipInteractor.privacyItems
@@ -150,45 +154,34 @@ constructor(
private val longerPattern = context.getString(R.string.abbrev_wday_month_day_no_year_alarm)
private val shorterPattern = context.getString(R.string.abbrev_month_day_no_year)
- private val longerDateFormat = MutableStateFlow(getFormatFromPattern(longerPattern))
- private val shorterDateFormat = MutableStateFlow(getFormatFromPattern(shorterPattern))
- private val _shorterDateText: MutableStateFlow<String> = MutableStateFlow("")
- val shorterDateText: StateFlow<String> = _shorterDateText.asStateFlow()
+ private val longerDateFormat: Flow<DateFormat> =
+ clockInteractor.onTimezoneOrLocaleChanged.mapLatest { getFormatFromPattern(longerPattern) }
+ private val shorterDateFormat: Flow<DateFormat> =
+ clockInteractor.onTimezoneOrLocaleChanged.mapLatest { getFormatFromPattern(shorterPattern) }
+
+ val longerDateText: String by
+ hydrator.hydratedStateOf(
+ traceName = "longerDateText",
+ initialValue = "",
+ source =
+ combine(longerDateFormat, clockInteractor.currentTime) { format, time ->
+ format.format(time)
+ },
+ )
- private val _longerDateText: MutableStateFlow<String> = MutableStateFlow("")
- val longerDateText: StateFlow<String> = _longerDateText.asStateFlow()
+ val shorterDateText: String by
+ hydrator.hydratedStateOf(
+ traceName = "shorterDateText",
+ initialValue = "",
+ source =
+ combine(shorterDateFormat, clockInteractor.currentTime) { format, time ->
+ format.format(time)
+ },
+ )
override suspend fun onActivated(): Nothing {
coroutineScope {
- launch {
- broadcastDispatcher
- .broadcastFlow(
- filter =
- IntentFilter().apply {
- addAction(Intent.ACTION_TIME_TICK)
- addAction(Intent.ACTION_TIME_CHANGED)
- addAction(Intent.ACTION_TIMEZONE_CHANGED)
- addAction(Intent.ACTION_LOCALE_CHANGED)
- },
- user = UserHandle.SYSTEM,
- map = { intent, _ ->
- intent.action == Intent.ACTION_TIMEZONE_CHANGED ||
- intent.action == Intent.ACTION_LOCALE_CHANGED
- },
- )
- .onEach { invalidateFormats -> updateDateTexts(invalidateFormats) }
- .launchIn(this)
- }
-
- launch { updateDateTexts(false) }
-
- launch {
- mobileIconsInteractor.filteredSubscriptions
- .map { list -> list.map { it.subscriptionId } }
- .collect { _mobileSubIds.value = it }
- }
-
launch { hydrator.activate() }
awaitCancellation()
@@ -260,26 +253,9 @@ constructor(
data object Strong : HeaderChipHighlight
}
- private fun updateDateTexts(invalidateFormats: Boolean) {
- if (invalidateFormats) {
- longerDateFormat.value = getFormatFromPattern(longerPattern)
- shorterDateFormat.value = getFormatFromPattern(shorterPattern)
- }
-
- val currentTime = Date()
-
- _longerDateText.value = longerDateFormat.value.format(currentTime)
- _shorterDateText.value = shorterDateFormat.value.format(currentTime)
- }
-
private fun getFormatFromPattern(pattern: String?): DateFormat {
- val l = Locale.getDefault()
- val format = DateFormat.getInstanceForSkeleton(pattern, l)
- // The use of CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE instead of
- // CAPITALIZATION_FOR_STANDALONE is to address
- // https://unicode-org.atlassian.net/browse/ICU-21631
- // TODO(b/229287642): Switch back to CAPITALIZATION_FOR_STANDALONE
- format.setContext(DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE)
+ val format = DateFormat.getInstanceForSkeleton(pattern, Locale.getDefault())
+ format.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE)
return format
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt
index dba8a9a6ddec..867db8ec8235 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt
@@ -163,6 +163,7 @@ constructor(
if (entry in nextMap) nextMap.remove(entry)
if (entry in nextList) nextList.remove(entry)
+ outcome = "add next"
addToNext(entry, runnable)
// Shorten headsUpEntryShowing display time
@@ -174,7 +175,7 @@ constructor(
headsUpEntryShowing!!.updateEntry(
/* updatePostTime= */ false,
/* updateEarliestRemovalTime= */ false,
- /* reason= */ "avalanche duration update",
+ /* reason= */ "shorten duration of previously-last HUN",
)
}
}
@@ -269,8 +270,10 @@ constructor(
}
nextList.sort()
val entryList = showingList + nextList
+ val thisKey = getKey(entry)
if (entryList.isEmpty()) {
- log { "No avalanche HUNs, use default ms: $autoDismissMs" }
+ headsUpManagerLogger.logAvalancheDuration(
+ thisKey, autoDismissMs, "No avalanche HUNs, use default", nextKey = "")
return autoDismissMs
}
// entryList.indexOf(entry) returns -1 even when the entry is in entryList
@@ -281,27 +284,29 @@ constructor(
}
}
if (thisEntryIndex == -1) {
- log { "Untracked entry, use default ms: $autoDismissMs" }
+ headsUpManagerLogger.logAvalancheDuration(
+ thisKey, autoDismissMs, "Untracked entry, use default", nextKey = "")
return autoDismissMs
}
val nextEntryIndex = thisEntryIndex + 1
-
- // If last entry, use default duration
if (nextEntryIndex >= entryList.size) {
- log { "Last entry, use default ms: $autoDismissMs" }
+ headsUpManagerLogger.logAvalancheDuration(
+ thisKey, autoDismissMs, "Last entry, use default", nextKey = "")
return autoDismissMs
}
val nextEntry = entryList[nextEntryIndex]
+ val nextKey = getKey(nextEntry)
if (nextEntry.compareNonTimeFields(entry) == -1) {
- // Next entry is higher priority
- log { "Next entry is higher priority: 500ms" }
+ headsUpManagerLogger.logAvalancheDuration(
+ thisKey, 500, "LOWER priority than next: ", nextKey)
return 500
} else if (nextEntry.compareNonTimeFields(entry) == 0) {
- // Next entry is same priority
- log { "Next entry is same priority: 1000ms" }
+ headsUpManagerLogger.logAvalancheDuration(
+ thisKey, 1000, "SAME priority as next: ", nextKey)
return 1000
} else {
- log { "Next entry is lower priority, use default ms: $autoDismissMs" }
+ headsUpManagerLogger.logAvalancheDuration(
+ thisKey, autoDismissMs, "HIGHER priority than next: ", nextKey)
return autoDismissMs
}
}
@@ -355,25 +360,28 @@ constructor(
}
private fun showNow(entry: HeadsUpEntry, runnableList: MutableList<Runnable>) {
- log { "SHOW: " + getKey(entry) }
-
+ headsUpManagerLogger.logAvalancheStage("show", getKey(entry))
uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_SHOWN)
headsUpEntryShowing = entry
- runnableList.forEach {
- if (it in debugRunnableLabelMap) {
- log { "RUNNABLE: ${debugRunnableLabelMap[it]}" }
+ runnableList.forEach { runnable ->
+ if (debug) {
+ debugRunnableLabelMap[runnable]?.let { label ->
+ headsUpManagerLogger.logAvalancheStage("run", label)
+ // Remove label after logging to avoid memory leak
+ debugRunnableLabelMap.remove(runnable)
+ }
}
- it.run()
+ runnable.run()
}
}
private fun showNext() {
- log { "SHOW NEXT" }
+ headsUpManagerLogger.logAvalancheStage("show next", key = "")
headsUpEntryShowing = null
if (nextList.isEmpty()) {
- log { "NO MORE TO SHOW" }
+ headsUpManagerLogger.logAvalancheStage("no more", key = "")
previousHunKey = ""
return
}
@@ -395,11 +403,7 @@ constructor(
debugRunnableLabelMap.remove(r)
}
}
- val queue = ArrayList<String>()
- for (entry in listToDrop) {
- queue.add("[${getKey(entry)}]")
- }
- val dropList = java.lang.String.join("\n", queue)
+ val dropList = listToDrop.joinToString("\n ") { getKey(it) }
headsUpManagerLogger.logDroppedHuns(dropList)
}
clearNext()
@@ -424,38 +428,24 @@ constructor(
// Methods below are for logging only ==========================================================
- private inline fun log(s: () -> String) {
- if (debug) {
- Log.d(tag, s())
- }
- }
-
private fun getStateStr(): String {
- return "\navalanche state:" +
- "\n\tshowing: [${getKey(headsUpEntryShowing)}]" +
- "\n\tprevious: [$previousHunKey]" +
- "\n\tnext list: $nextListStr" +
- "\n\tnext map: $nextMapStr" +
- "\nBHUM.mHeadsUpEntryMap: " +
- baseEntryMapStr()
+ return "\n[AC state]" +
+ "\nshow: ${getKey(headsUpEntryShowing)}" +
+ "\nprevious: $previousHunKey" +
+ "\n$nextStr" +
+ "\n[HeadsUpManagerImpl.mHeadsUpEntryMap] " + baseEntryMapStr() + "\n"
}
- private val nextListStr: String
+ private val nextStr: String
get() {
- val queue = ArrayList<String>()
- for (entry in nextList) {
- queue.add("[${getKey(entry)}]")
+ val nextListStr = nextList.joinToString("\n ") { getKey(it) }
+ if (nextList.toSet() == nextMap.keys.toSet()) {
+ return "next (${nextList.size}):\n $nextListStr"
}
- return java.lang.String.join("\n", queue)
- }
-
- private val nextMapStr: String
- get() {
- val queue = ArrayList<String>()
- for (entry in nextMap.keys) {
- queue.add("[${getKey(entry)}]")
- }
- return java.lang.String.join("\n", queue)
+ // This should never happen
+ val nextMapStr = nextMap.keys.joinToString("\n ") { getKey(it) }
+ return "next list (${nextList.size}):\n $nextListStr" +
+ "\nnext map (${nextMap.size}):\n $nextMapStr"
}
fun getKey(entry: HeadsUpEntry?): String {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
index 7d74a496853f..87b9bf87c680 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
@@ -856,11 +856,11 @@ public class HeadsUpManagerImpl
private String getEntryMapStr() {
if (mHeadsUpEntryMap.isEmpty()) {
- return "EMPTY";
+ return "";
}
StringBuilder entryMapStr = new StringBuilder();
for (HeadsUpEntry entry: mHeadsUpEntryMap.values()) {
- entryMapStr.append("\n\t").append(
+ entryMapStr.append("\n ").append(
entry.mEntry == null ? "null" : entry.mEntry.getKey());
}
return entryMapStr.toString();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt
index 65fb9ca558d7..388d357b3b15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt
@@ -71,7 +71,7 @@ constructor(@NotificationHeadsUpLog private val buffer: LogBuffer) {
str3 = outcome
bool1 = isEnabled
},
- { "$str1\n\t=> AC[isEnabled:$bool1] update: $str2\n\t=> $str3" },
+ { "$str1\n=> AC[enabled:$bool1] update: $str2\n=> $str3" },
)
}
@@ -90,7 +90,33 @@ constructor(@NotificationHeadsUpLog private val buffer: LogBuffer) {
str3 = outcome
bool1 = isEnabled
},
- { "$str1\n\t=> AC[isEnabled:$bool1] delete: $str2\n\t=> $str3" },
+ { "$str1\n=> AC[enabled:$bool1] delete: $str2\n=> $str3" },
+ )
+ }
+
+ fun logAvalancheStage(stage: String, key: String) {
+ buffer.log(
+ TAG,
+ INFO,
+ {
+ str1 = stage
+ str2 = key
+ },
+ { "[AC] $str1 $str2" },
+ )
+ }
+
+ fun logAvalancheDuration(thisKey: String, duration: Int, reason: String, nextKey: String) {
+ buffer.log(
+ TAG,
+ INFO,
+ {
+ str1 = thisKey
+ int1 = duration
+ str2 = reason
+ str3 = nextKey
+ },
+ { "[AC] $str1 | $int1 ms | $str2 $str3" },
)
}
@@ -325,7 +351,7 @@ constructor(@NotificationHeadsUpLog private val buffer: LogBuffer) {
}
fun logDroppedHuns(entryList: String) {
- buffer.log(TAG, VERBOSE, { str1 = entryList }, { "[AC] Drop HUNs: $str1" })
+ buffer.log(TAG, VERBOSE, { str1 = entryList }, { "[AC] dropped:\n $str1" })
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index c0ebe7dd7023..5c81c8e22bfc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -49,6 +49,7 @@ import com.android.systemui.keyguard.ui.viewmodel.AodToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToPrimaryBouncerTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.DozingToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DozingToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DozingToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DozingToOccludedTransitionViewModel
@@ -139,6 +140,7 @@ constructor(
private val aodToOccludedTransitionViewModel: AodToOccludedTransitionViewModel,
private val aodToGlanceableHubTransitionViewModel: AodToGlanceableHubTransitionViewModel,
private val aodToPrimaryBouncerTransitionViewModel: AodToPrimaryBouncerTransitionViewModel,
+ private val dozingToDreamingTransitionViewModel: DozingToDreamingTransitionViewModel,
dozingToGlanceableHubTransitionViewModel: DozingToGlanceableHubTransitionViewModel,
private val dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
private val dozingToOccludedTransitionViewModel: DozingToOccludedTransitionViewModel,
@@ -577,6 +579,7 @@ constructor(
aodToOccludedTransitionViewModel.lockscreenAlpha(viewState),
aodToGlanceableHubTransitionViewModel.lockscreenAlpha(viewState),
aodToPrimaryBouncerTransitionViewModel.notificationAlpha,
+ dozingToDreamingTransitionViewModel.notificationAlpha,
dozingToLockscreenTransitionViewModel.lockscreenAlpha,
dozingToOccludedTransitionViewModel.lockscreenAlpha(viewState),
dozingToPrimaryBouncerTransitionViewModel.notificationAlpha,
diff --git a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
index 32f2ca6fb696..367f54cf4936 100644
--- a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
@@ -147,7 +147,7 @@ public class CreateUserActivity extends Activity {
super.onDestroy();
}
- private void addUserNow(String userName, Drawable userIcon, Boolean isAdmin) {
+ private void addUserNow(String userName, Drawable userIcon, String iconPath, Boolean isAdmin) {
mSetupUserDialog.dismiss();
userName = (userName == null || userName.trim().isEmpty())
? getString(com.android.settingslib.R.string.user_new_user_name)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorKosmos.kt
index 6fd7cf6edbe4..2ea2119970ad 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorKosmos.kt
@@ -16,14 +16,18 @@
package com.android.systemui.shade.domain.interactor
+import com.android.systemui.broadcast.broadcastDispatcher
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.plugins.activityStarter
import com.android.systemui.shade.data.repository.shadeHeaderClockRepository
+import com.android.systemui.util.time.systemClock
var Kosmos.shadeHeaderClockInteractor: ShadeHeaderClockInteractor by
Kosmos.Fixture {
ShadeHeaderClockInteractor(
repository = shadeHeaderClockRepository,
activityStarter = activityStarter,
+ broadcastDispatcher = broadcastDispatcher,
+ systemClock = systemClock,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt
index 08de73be1128..2f8387b2d0f9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt
@@ -18,7 +18,6 @@ package com.android.systemui.shade.ui.viewmodel
import android.content.applicationContext
import com.android.systemui.battery.batteryMeterViewControllerFactory
-import com.android.systemui.broadcast.broadcastDispatcher
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.plugins.activityStarter
import com.android.systemui.scene.domain.interactor.sceneInteractor
@@ -50,7 +49,6 @@ val Kosmos.shadeHeaderViewModel: ShadeHeaderViewModel by
statusBarIconController = mock<StatusBarIconController>(),
notificationIconContainerStatusBarViewBinder =
mock<NotificationIconContainerStatusBarViewBinder>(),
- broadcastDispatcher = broadcastDispatcher,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
index 17ef208fe12e..51bb94fd2ab9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
@@ -30,6 +30,7 @@ import com.android.systemui.keyguard.ui.viewmodel.aodToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.aodToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.aodToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.aodToPrimaryBouncerTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.dozingToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.dozingToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.dozingToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.dozingToOccludedTransitionViewModel
@@ -83,6 +84,7 @@ val Kosmos.sharedNotificationContainerViewModel by Fixture {
aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
aodToOccludedTransitionViewModel = aodToOccludedTransitionViewModel,
aodToPrimaryBouncerTransitionViewModel = aodToPrimaryBouncerTransitionViewModel,
+ dozingToDreamingTransitionViewModel = dozingToDreamingTransitionViewModel,
dozingToGlanceableHubTransitionViewModel = dozingToGlanceableHubTransitionViewModel,
dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel,
dozingToOccludedTransitionViewModel = dozingToOccludedTransitionViewModel,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt
index 06af32e69b75..b23ccbfbd93f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt
@@ -14,12 +14,15 @@
* limitations under the License.
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
package com.android.systemui.util.time
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.currentTime
var Kosmos.systemClock by
@@ -27,6 +30,7 @@ var Kosmos.systemClock by
mock {
whenever(elapsedRealtime()).thenAnswer { testScope.currentTime }
whenever(uptimeMillis()).thenAnswer { testScope.currentTime }
+ whenever(currentTimeMillis()).thenAnswer { testScope.currentTime }
}
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index b677297dfef2..4bfee1d8398f 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -1464,7 +1464,10 @@ public class CachedAppOptimizer {
void onProcessFrozen(ProcessRecord frozenProc) {
if (useCompaction()) {
synchronized (mProcLock) {
- compactApp(frozenProc, CompactProfile.FULL, CompactSource.APP, false);
+ // only full-compact if process is cached
+ if (frozenProc.mState.getSetAdj() >= mCompactThrottleMinOomAdj) {
+ compactApp(frozenProc, CompactProfile.FULL, CompactSource.APP, false);
+ }
}
}
frozenProc.onProcessFrozen();
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 88f5c81231b8..c41b8db1ce75 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -333,7 +333,7 @@ public class AutomaticBrightnessController {
int ambientLightHorizonLong, float userLux, float userNits,
DisplayManagerFlags displayManagerFlags) {
mInjector = injector;
- mClock = injector.createClock(displayManagerFlags.offloadControlsDozeAutoBrightness());
+ mClock = injector.createClock();
mContext = context;
mCallbacks = callbacks;
mSensorManager = sensorManager;
@@ -1402,8 +1402,7 @@ public class AutomaticBrightnessController {
public void onSensorChanged(SensorEvent event) {
if (mLightSensorEnabled) {
// The time received from the sensor is in nano seconds, hence changing it to ms
- final long time = (mDisplayManagerFlags.offloadControlsDozeAutoBrightness())
- ? TimeUnit.NANOSECONDS.toMillis(event.timestamp) : mClock.uptimeMillis();
+ final long time = TimeUnit.NANOSECONDS.toMillis(event.timestamp);
final float lux = event.values[0];
handleLightSensorEvent(time, lux);
}
@@ -1616,20 +1615,13 @@ public class AutomaticBrightnessController {
}
private static class RealClock implements Clock {
- private final boolean mOffloadControlsDozeBrightness;
-
- RealClock(boolean offloadControlsDozeBrightness) {
- mOffloadControlsDozeBrightness = offloadControlsDozeBrightness;
- }
-
@Override
public long uptimeMillis() {
return SystemClock.uptimeMillis();
}
public long getSensorEventScaleTime() {
- return (mOffloadControlsDozeBrightness)
- ? SystemClock.elapsedRealtime() : uptimeMillis();
+ return SystemClock.elapsedRealtime();
}
}
@@ -1638,8 +1630,8 @@ public class AutomaticBrightnessController {
return BackgroundThread.getHandler();
}
- Clock createClock(boolean offloadControlsDozeBrightness) {
- return new RealClock(offloadControlsDozeBrightness);
+ Clock createClock() {
+ return new RealClock();
}
}
}
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
index 2c6f37448735..6510441ba28f 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
@@ -291,8 +291,7 @@ public class DisplayBrightnessStrategySelector {
void setAllowAutoBrightnessWhileDozing(
DisplayManagerInternal.DisplayOffloadSession displayOffloadSession) {
mAllowAutoBrightnessWhileDozing = mAllowAutoBrightnessWhileDozingConfig;
- if (mDisplayManagerFlags.offloadControlsDozeAutoBrightness()
- && mDisplayManagerFlags.isDisplayOffloadEnabled()
+ if (mDisplayManagerFlags.isDisplayOffloadEnabled()
&& displayOffloadSession != null) {
mAllowAutoBrightnessWhileDozing &= displayOffloadSession.allowAutoBrightnessInDoze();
}
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index e4b595ab7c55..c3057ded66eb 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -156,11 +156,6 @@ public class DisplayManagerFlags {
Flags.FLAG_DOZE_BRIGHTNESS_FLOAT,
Flags::dozeBrightnessFloat);
- private final FlagState mOffloadControlsDozeAutoBrightness = new FlagState(
- Flags.FLAG_OFFLOAD_CONTROLS_DOZE_AUTO_BRIGHTNESS,
- Flags::offloadControlsDozeAutoBrightness
- );
-
private final FlagState mPeakRefreshRatePhysicalLimit = new FlagState(
Flags.FLAG_ENABLE_PEAK_REFRESH_RATE_PHYSICAL_LIMIT,
Flags::enablePeakRefreshRatePhysicalLimit
@@ -440,13 +435,6 @@ public class DisplayManagerFlags {
return mDozeBrightnessFloat.isEnabled();
}
- /**
- * @return Whether DisplayOffload should control auto-brightness in doze
- */
- public boolean offloadControlsDozeAutoBrightness() {
- return mOffloadControlsDozeAutoBrightness.isEnabled();
- }
-
public boolean isPeakRefreshRatePhysicalLimitEnabled() {
return mPeakRefreshRatePhysicalLimit.isEnabled();
}
@@ -647,7 +635,6 @@ public class DisplayManagerFlags {
pw.println(" " + mResolutionBackupRestore);
pw.println(" " + mUseFusionProxSensor);
pw.println(" " + mDozeBrightnessFloat);
- pw.println(" " + mOffloadControlsDozeAutoBrightness);
pw.println(" " + mPeakRefreshRatePhysicalLimit);
pw.println(" " + mIgnoreAppPreferredRefreshRate);
pw.println(" " + mSynthetic60hzModes);
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index acdc0e0cf891..f5451307afb7 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -255,17 +255,6 @@ flag {
}
flag {
- name: "offload_controls_doze_auto_brightness"
- namespace: "display_manager"
- description: "Allows the registered DisplayOffloader to control if auto-brightness is used in doze"
- bug: "327392714"
- is_fixed_read_only: true
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "enable_peak_refresh_rate_physical_limit"
namespace: "display_manager"
description: "Flag for adding physical refresh rate limit if smooth display setting is on "
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 7e8bb28b6a37..2af74f620c95 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -569,7 +569,8 @@ public final class DreamManagerService extends SystemService {
}
private void requestDreamInternal() {
- if (isDreamingInternal() && !dreamIsFrontmost() && mController.bringDreamToFront()) {
+ if (isDreamingInternal() && !dreamIsFrontmost() && mController.bringDreamToFront()
+ && !isDozingInternal()) {
return;
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS b/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
index bb487fb52c9f..ebf7e6bed064 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
@@ -1,4 +1,3 @@
aseemk@google.com
bozhu@google.com
dementyev@google.com
-robertberry@google.com
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 76c5240ab623..95ac908efcf0 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1163,6 +1163,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ private boolean shouldShowHub() {
+ final boolean hubEnabled = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(), Settings.Secure.GLANCEABLE_HUB_ENABLED,
+ 1, mCurrentUserId) == 1;
+
+ return mUserManagerInternal != null && mUserManagerInternal.isUserUnlocked(mCurrentUserId)
+ && hubEnabled && mDreamManagerInternal.dreamConditionActive();
+ }
+
@VisibleForTesting
void powerPress(long eventTime, int count, int displayId) {
// SideFPS still needs to know about suppressed power buttons, in case it needs to block
@@ -1251,7 +1260,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mContext.getContentResolver(), Settings.Secure.GLANCEABLE_HUB_ENABLED,
1, mCurrentUserId) == 1;
- if (mDreamManagerInternal.isDreaming() || isKeyguardShowing()) {
+ if ((mDreamManagerInternal != null && mDreamManagerInternal.isDreaming())
+ || isKeyguardShowing()) {
// If the device is already dreaming or on keyguard, go to sleep.
sleepDefaultDisplayFromPowerButton(eventTime, 0);
break;
@@ -1261,9 +1271,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// show hub.
boolean keyguardAvailable = !mLockPatternUtils.isLockScreenDisabled(
mCurrentUserId);
- if (mUserManagerInternal.isUserUnlocked(mCurrentUserId) && hubEnabled
- && keyguardAvailable && mDreamManagerInternal.dreamConditionActive()) {
- // If the hub can be launched, send a message to keyguard.
+ if (shouldShowHub() && keyguardAvailable) {
+ // If the hub can be launched, send a message to keyguard. We do not know if
+ // the hub is already running or not, keyguard handles turning screen off if
+ // it is.
Bundle options = new Bundle();
options.putBoolean(EXTRA_TRIGGER_HUB, true);
lockNow(options);
@@ -1324,14 +1335,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
* @param isScreenOn Whether the screen is currently on.
* @param noDreamAction The action to perform if dreaming is not possible.
*/
- private void attemptToDreamFromShortPowerButtonPress(
+ private boolean attemptToDreamFromShortPowerButtonPress(
boolean isScreenOn, Runnable noDreamAction) {
if (mShortPressOnPowerBehavior != SHORT_PRESS_POWER_DREAM_OR_SLEEP
&& mShortPressOnPowerBehavior != SHORT_PRESS_POWER_HUB_OR_DREAM_OR_SLEEP) {
// If the power button behavior isn't one that should be able to trigger the dream, give
// up.
noDreamAction.run();
- return;
+ return false;
}
final DreamManagerInternal dreamManagerInternal = getDreamManagerInternal();
@@ -1339,7 +1350,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Slog.d(TAG, "Can't start dreaming when attempting to dream from short power"
+ " press (isScreenOn=" + isScreenOn + ")");
noDreamAction.run();
- return;
+ return false;
}
synchronized (mLock) {
@@ -1350,6 +1361,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
dreamManagerInternal.requestDream();
+
+ return true;
}
/**
@@ -2327,6 +2340,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowWakeUpPolicy getWindowWakeUpPolicy() {
return new WindowWakeUpPolicy(mContext);
}
+
+ DreamManagerInternal getDreamManagerInternal() {
+ return LocalServices.getService(DreamManagerInternal.class);
+ }
}
/** {@inheritDoc} */
@@ -2345,7 +2362,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mInputManager = mContext.getSystemService(InputManager.class);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
- mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
+ mDreamManagerInternal = injector.getDreamManagerInternal();
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mSensorPrivacyManager = mContext.getSystemService(SensorPrivacyManager.class);
@@ -6398,6 +6415,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
event.getDisplayId(), event.getKeyCode(), "wakeUpFromWakeKey")) {
return;
}
+
+ if (!shouldShowHub()
+ && mShortPressOnPowerBehavior == SHORT_PRESS_POWER_HUB_OR_DREAM_OR_SLEEP
+ && event.getKeyCode() == KEYCODE_POWER
+ && attemptToDreamFromShortPowerButtonPress(false, () -> {})) {
+ // In the case that we should wake to dream and successfully initiate dreaming, do not
+ // continue waking up. Doing so will exit the dream state and cause UI to react
+ // accordingly.
+ return;
+ }
+
wakeUpFromWakeKey(
event.getEventTime(),
event.getKeyCode(),
diff --git a/services/core/java/com/android/server/power/stats/processor/BinaryStatePowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/BinaryStatePowerStatsProcessor.java
index 5eaaac9570d5..c89dddf45609 100644
--- a/services/core/java/com/android/server/power/stats/processor/BinaryStatePowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/BinaryStatePowerStatsProcessor.java
@@ -274,12 +274,13 @@ abstract class BinaryStatePowerStatsProcessor extends PowerStatsProcessor {
int uid = uids.get(k);
if (stats.getUidStats(mTmpUidStatsArray, uid,
proportionalEstimate.stateValues)) {
- double power = intermediates.power
- * mStatsLayout.getUidUsageDuration(mTmpUidStatsArray)
- / intermediates.duration;
- mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
- stats.setUidStats(uid, proportionalEstimate.stateValues,
- mTmpUidStatsArray);
+ long duration = mStatsLayout.getUidUsageDuration(mTmpUidStatsArray);
+ if (duration != 0) {
+ double power = intermediates.power * duration / intermediates.duration;
+ mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, proportionalEstimate.stateValues,
+ mTmpUidStatsArray);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/power/stats/processor/BluetoothPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/BluetoothPowerStatsProcessor.java
index 9e8b553dfe29..c1cd3acf1656 100644
--- a/services/core/java/com/android/server/power/stats/processor/BluetoothPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/BluetoothPowerStatsProcessor.java
@@ -299,8 +299,10 @@ class BluetoothPowerStatsProcessor extends PowerStatsProcessor {
/ intermediates.txBytes;
}
}
- mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
- stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ if (power != 0) {
+ mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/power/stats/processor/CpuPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/CpuPowerStatsProcessor.java
index b442dc2655d4..6ce2cf738192 100644
--- a/services/core/java/com/android/server/power/stats/processor/CpuPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/CpuPowerStatsProcessor.java
@@ -545,8 +545,10 @@ class CpuPowerStatsProcessor extends PowerStatsProcessor {
power = Math.max(0, power - wakelockPowerEstimate);
}
- mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
- stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ if (power != 0) {
+ mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/power/stats/processor/CustomEnergyConsumerPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/CustomEnergyConsumerPowerStatsProcessor.java
index 05865e2074dd..76ea7e841106 100644
--- a/services/core/java/com/android/server/power/stats/processor/CustomEnergyConsumerPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/CustomEnergyConsumerPowerStatsProcessor.java
@@ -72,9 +72,12 @@ class CustomEnergyConsumerPowerStatsProcessor extends PowerStatsProcessor {
int uid = uids.get(k);
if (stats.getUidStats(mTmpUidStatsArray, uid,
proportionalEstimate.stateValues)) {
- sLayout.setUidPowerEstimate(mTmpUidStatsArray,
- uCtoMah(sLayout.getUidConsumedEnergy(mTmpUidStatsArray, 0)));
- stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ double power = uCtoMah(sLayout.getUidConsumedEnergy(mTmpUidStatsArray, 0));
+ if (power != 0) {
+ sLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, proportionalEstimate.stateValues,
+ mTmpUidStatsArray);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/power/stats/processor/MobileRadioPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/MobileRadioPowerStatsProcessor.java
index c5db19bb3f32..a544daad82f1 100644
--- a/services/core/java/com/android/server/power/stats/processor/MobileRadioPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/MobileRadioPowerStatsProcessor.java
@@ -383,8 +383,10 @@ class MobileRadioPowerStatsProcessor extends PowerStatsProcessor {
/ intermediates.txPackets;
}
- mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
- stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ if (power != 0) {
+ mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ }
if (DEBUG) {
Slog.d(TAG, "UID: " + uid
diff --git a/services/core/java/com/android/server/power/stats/processor/MultiStateStats.java b/services/core/java/com/android/server/power/stats/processor/MultiStateStats.java
index 28474a554b38..69325757c79d 100644
--- a/services/core/java/com/android/server/power/stats/processor/MultiStateStats.java
+++ b/services/core/java/com/android/server/power/stats/processor/MultiStateStats.java
@@ -16,6 +16,7 @@
package com.android.server.power.stats.processor;
+import android.annotation.Nullable;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -333,9 +334,9 @@ class MultiStateStats {
/**
* Adds the delta to the metrics. The number of values must correspond to the dimension count
- * supplied to the Factory constructor
+ * supplied to the Factory constructor. Null values is equivalent to an array of zeros.
*/
- void increment(long[] values, long timestampMs) {
+ void increment(@Nullable long[] values, long timestampMs) {
mCounter.incrementValues(values, timestampMs);
mTracking = true;
}
diff --git a/services/core/java/com/android/server/power/stats/processor/PowerComponentAggregatedPowerStats.java b/services/core/java/com/android/server/power/stats/processor/PowerComponentAggregatedPowerStats.java
index 33baad8cc441..f9b9da9171cb 100644
--- a/services/core/java/com/android/server/power/stats/processor/PowerComponentAggregatedPowerStats.java
+++ b/services/core/java/com/android/server/power/stats/processor/PowerComponentAggregatedPowerStats.java
@@ -72,7 +72,6 @@ class PowerComponentAggregatedPowerStats {
private MultiStateStats mDeviceStats;
private final SparseArray<MultiStateStats> mStateStats = new SparseArray<>();
private final SparseArray<UidStats> mUidStats = new SparseArray<>();
- private long[] mZeroArray;
private static class UidStats {
public int[] states;
@@ -251,11 +250,8 @@ class PowerComponentAggregatedPowerStats {
for (int i = mUidStats.size() - 1; i >= 0; i--) {
PowerComponentAggregatedPowerStats.UidStats uidStats = mUidStats.valueAt(i);
if (!uidStats.updated && uidStats.stats != null) {
- if (mZeroArray == null
- || mZeroArray.length != mPowerStatsDescriptor.uidStatsArrayLength) {
- mZeroArray = new long[mPowerStatsDescriptor.uidStatsArrayLength];
- }
- uidStats.stats.increment(mZeroArray, timestampMs);
+ // Null stands for an array of zeros
+ uidStats.stats.increment(null, timestampMs);
}
uidStats.updated = false;
}
diff --git a/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java
index 5a8e8b40bc3c..9df3d7eea27b 100644
--- a/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java
@@ -230,9 +230,11 @@ class ScreenPowerStatsProcessor extends PowerStatsProcessor {
int uid = uids.get(j);
if (stats.getUidStats(mTmpUidStatsArray, uid, uidStateValues)) {
long duration = mStatsLayout.getUidTopActivityDuration(mTmpUidStatsArray);
- double power = intermediates.power * duration / totalTopActivityDuration;
- mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
- stats.setUidStats(uid, uidStateValues, mTmpUidStatsArray);
+ if (duration != 0) {
+ double power = intermediates.power * duration / totalTopActivityDuration;
+ mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, uidStateValues, mTmpUidStatsArray);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/power/stats/processor/WifiPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/WifiPowerStatsProcessor.java
index f1797bd2301d..8cc0b6eb6150 100644
--- a/services/core/java/com/android/server/power/stats/processor/WifiPowerStatsProcessor.java
+++ b/services/core/java/com/android/server/power/stats/processor/WifiPowerStatsProcessor.java
@@ -375,8 +375,10 @@ class WifiPowerStatsProcessor extends PowerStatsProcessor {
/ intermediates.batchedScanDuration;
}
}
- mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
- stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ if (power != 0) {
+ mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power);
+ stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray);
+ }
if (DEBUG) {
Slog.d(TAG, "UID: " + uid
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index a698a9e82929..bbda849262b2 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1910,7 +1910,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
if (!hasDirectChildActivities()) {
return false;
}
- if (mResumedActivity != null && mTransitionController.isTransientLaunch(mResumedActivity)) {
+ if (mResumedActivity != null && !mResumedActivity.finishing
+ && mTransitionController.isTransientLaunch(mResumedActivity)) {
// Even if the transient activity is occluded, defer pausing (addToStopping will still
// be called) it until the transient transition is done. So the current resuming
// activity won't need to wait for additional pause complete.
diff --git a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 7d25acd7f5e7..a42116351c2d 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -152,7 +152,7 @@ public class AutomaticBrightnessControllerTest {
}
@Override
- AutomaticBrightnessController.Clock createClock(boolean isEnabled) {
+ AutomaticBrightnessController.Clock createClock() {
return new AutomaticBrightnessController.Clock() {
@Override
public long uptimeMillis() {
@@ -618,39 +618,46 @@ public class AutomaticBrightnessControllerTest {
long increment = 500;
// set autobrightness to low
// t = 0
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
// t = 500
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
// t = 1000
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(0.0f, mController.getAmbientLux(), EPSILON);
// t = 1500
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(0.0f, mController.getAmbientLux(), EPSILON);
// t = 2000
// ensure that our reading is at 0.
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(0.0f, mController.getAmbientLux(), EPSILON);
// t = 2500
// first 10000 lux sensor event reading
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertTrue(mController.getAmbientLux() > 0.0f);
assertTrue(mController.getAmbientLux() < 10000.0f);
// t = 3000
// lux reading should still not yet be 10000.
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertTrue(mController.getAmbientLux() > 0.0f);
assertTrue(mController.getAmbientLux() < 10000.0f);
@@ -659,45 +666,53 @@ public class AutomaticBrightnessControllerTest {
// lux has been high (10000) for 1000ms.
// lux reading should be 10000
// short horizon (ambient lux) is high, long horizon is still not high
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(10000.0f, mController.getAmbientLux(), EPSILON);
// t = 4000
// stay high
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(10000.0f, mController.getAmbientLux(), EPSILON);
// t = 4500
Mockito.clearInvocations(mBrightnessMappingStrategy);
mClock.fastForward(increment);
// short horizon is high, long horizon is high too
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
verify(mBrightnessMappingStrategy, times(1)).getBrightness(10000, null, -1);
assertEquals(10000.0f, mController.getAmbientLux(), EPSILON);
// t = 5000
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertTrue(mController.getAmbientLux() > 0.0f);
assertTrue(mController.getAmbientLux() < 10000.0f);
// t = 5500
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertTrue(mController.getAmbientLux() > 0.0f);
assertTrue(mController.getAmbientLux() < 10000.0f);
// t = 6000
mClock.fastForward(increment);
// ambient lux goes to 0
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(0.0f, mController.getAmbientLux(), EPSILON);
// only the values within the horizon should be kept
assertArrayEquals(new float[] {10000, 10000, 0, 0, 0}, mController.getLastSensorValues(),
EPSILON);
- assertArrayEquals(new long[] {4000, 4500, 5000, 5500, 6000},
+ assertArrayEquals(new long[]{4000 + ANDROID_SLEEP_TIME, 4500 + ANDROID_SLEEP_TIME,
+ 5000 + ANDROID_SLEEP_TIME, 5500 + ANDROID_SLEEP_TIME,
+ 6000 + ANDROID_SLEEP_TIME},
mController.getLastSensorTimestamps());
}
@@ -793,7 +808,8 @@ public class AutomaticBrightnessControllerTest {
for (int i = 0; i < 1000; i++) {
lux += increment;
mClock.fastForward(increment);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
}
int valuesCount = (int) Math.ceil((double) AMBIENT_LIGHT_HORIZON_LONG / increment + 1);
@@ -807,17 +823,17 @@ public class AutomaticBrightnessControllerTest {
long sensorTimestamp = mClock.now();
for (int i = valuesCount - 1; i >= 1; i--) {
assertEquals(lux, sensorValues[i], EPSILON);
- assertEquals(sensorTimestamp, sensorTimestamps[i]);
+ assertEquals(sensorTimestamp + ANDROID_SLEEP_TIME, sensorTimestamps[i]);
lux -= increment;
sensorTimestamp -= increment;
}
assertEquals(lux, sensorValues[0], EPSILON);
- assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG, sensorTimestamps[0]);
+ assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG + ANDROID_SLEEP_TIME,
+ sensorTimestamps[0]);
}
@Test
public void testAmbientLuxBuffers_prunedBeyondLongHorizonExceptLatestValue() throws Exception {
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
ArgumentCaptor<SensorEventListener> listenerCaptor =
ArgumentCaptor.forClass(SensorEventListener.class);
verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
@@ -867,7 +883,8 @@ public class AutomaticBrightnessControllerTest {
for (int i = 0; i < 20; i++) {
lux += increment1;
mClock.fastForward(increment1);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
}
int valuesCount = (int) Math.ceil((double) AMBIENT_LIGHT_HORIZON_LONG / increment1 + 1);
@@ -877,7 +894,8 @@ public class AutomaticBrightnessControllerTest {
for (int i = 0; i < initialCapacity - valuesCount; i++) {
lux += increment2;
mClock.fastForward(increment2);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
}
float[] sensorValues = mController.getLastSensorValues();
@@ -890,7 +908,7 @@ public class AutomaticBrightnessControllerTest {
long sensorTimestamp = mClock.now();
for (int i = initialCapacity - 1; i >= 1; i--) {
assertEquals(lux, sensorValues[i], EPSILON);
- assertEquals(sensorTimestamp, sensorTimestamps[i]);
+ assertEquals(sensorTimestamp + ANDROID_SLEEP_TIME, sensorTimestamps[i]);
if (i >= valuesCount) {
lux -= increment2;
@@ -901,7 +919,8 @@ public class AutomaticBrightnessControllerTest {
}
}
assertEquals(lux, sensorValues[0], EPSILON);
- assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG, sensorTimestamps[0]);
+ assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG + ANDROID_SLEEP_TIME,
+ sensorTimestamps[0]);
}
@Test
@@ -951,25 +970,29 @@ public class AutomaticBrightnessControllerTest {
// t = 0
// Initial lux
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(500, mController.getAmbientLux(), EPSILON);
// t = 1000
// Lux isn't steady yet
mClock.fastForward(1000);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(500, mController.getAmbientLux(), EPSILON);
// t = 1500
// Lux isn't steady yet
mClock.fastForward(500);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(500, mController.getAmbientLux(), EPSILON);
// t = 2500
// Lux is steady now
mClock.fastForward(1000);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(1200, mController.getAmbientLux(), EPSILON);
}
@@ -992,25 +1015,29 @@ public class AutomaticBrightnessControllerTest {
// t = 0
// Initial lux
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(1200, mController.getAmbientLux(), EPSILON);
// t = 2000
// Lux isn't steady yet
mClock.fastForward(2000);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(1200, mController.getAmbientLux(), EPSILON);
// t = 2500
// Lux isn't steady yet
mClock.fastForward(500);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(1200, mController.getAmbientLux(), EPSILON);
// t = 4500
// Lux is steady now
mClock.fastForward(2000);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(500, mController.getAmbientLux(), EPSILON);
}
@@ -1031,19 +1058,22 @@ public class AutomaticBrightnessControllerTest {
// t = 0
// Initial lux
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(500, mController.getAmbientLux(), EPSILON);
// t = 500
// Lux isn't steady yet
mClock.fastForward(500);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(500, mController.getAmbientLux(), EPSILON);
// t = 1500
// Lux is steady now
mClock.fastForward(1000);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(1200, mController.getAmbientLux(), EPSILON);
}
@@ -1068,19 +1098,22 @@ public class AutomaticBrightnessControllerTest {
// t = 0
// Initial lux
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(1200, mController.getAmbientLux(), EPSILON);
// t = 1000
// Lux isn't steady yet
mClock.fastForward(1000);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(1200, mController.getAmbientLux(), EPSILON);
// t = 2500
// Lux is steady now
mClock.fastForward(1500);
- listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500,
+ (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
assertEquals(500, mController.getAmbientLux(), EPSILON);
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index aed1f9858660..db94958f769e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1066,7 +1066,6 @@ public final class DisplayPowerControllerTest {
com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true);
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
- when(mDisplayManagerFlagsMock.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true);
mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
@@ -1172,7 +1171,6 @@ public final class DisplayPowerControllerTest {
com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true);
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
- when(mDisplayManagerFlagsMock.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(false);
mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
index 2ebb6c2a3ce4..ef39167dbabc 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
@@ -240,7 +240,6 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void selectStrategyDoesNotSelectDozeStrategyWhenOffloadSessionAutoBrightnessIsEnabled() {
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true);
when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
@@ -378,7 +377,6 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void selectStrategy_selectsAutomaticStrategyWhenValid() {
when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true);
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true);
when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
@@ -409,7 +407,6 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void selectStrategy_doesNotSelectAutomaticStrategyWhenStylusInUse() {
when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true);
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true);
when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
@@ -536,7 +533,6 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void setAllowAutoBrightnessWhileDozing_enabledWhenConfigAndOffloadSessionAreEnabled() {
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true);
when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
@@ -550,7 +546,6 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void setAllowAutoBrightnessWhileDozing_disabledWhenOffloadSessionFlagIsDisabled() {
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(false);
when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
@@ -564,7 +559,6 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void setAllowAutoBrightnessWhileDozing_disabledWhenABWhileDozingConfigIsDisabled() {
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true);
when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
@@ -588,7 +582,6 @@ public final class DisplayBrightnessStrategySelectorTest {
@Test
public void setAllowAutoBrightnessWhileDozing_EnabledWhenFlagsAreDisabled() {
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
true);
mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext,
@@ -600,11 +593,5 @@ public final class DisplayBrightnessStrategySelectorTest {
mDisplayBrightnessStrategySelector
.setAllowAutoBrightnessWhileDozing(mDisplayOffloadSession);
assertTrue(mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozing());
-
- when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true);
- when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(false);
- mDisplayBrightnessStrategySelector
- .setAllowAutoBrightnessWhileDozing(mDisplayOffloadSession);
- assertTrue(mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozing());
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
index fa5847560782..4b53f1309337 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
@@ -23,18 +23,11 @@ import static com.android.server.am.ActivityManagerService.Injector;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.FrozenProcessListener;
import android.content.ComponentName;
import android.content.Context;
@@ -44,14 +37,12 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.MessageQueue;
import android.os.Process;
-import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
import android.text.TextUtils;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.internal.annotations.GuardedBy;
import com.android.modules.utils.testing.ExtendedMockitoRule;
import com.android.modules.utils.testing.TestableDeviceConfig;
import com.android.server.LocalServices;
@@ -68,11 +59,9 @@ import org.mockito.Mock;
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
/**
@@ -164,7 +153,7 @@ public final class CachedAppOptimizerTest {
app.info.uid = packageUid;
// Exact value does not mater, it can be any state for which compaction is allowed.
app.mState.setSetProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
- app.mState.setSetAdj(899);
+ app.mState.setSetAdj(940);
app.mState.setCurAdj(940);
return app;
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java
index 8fc8c9f677a6..6be9c6d4b80c 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java
@@ -48,6 +48,7 @@ import org.junit.runner.RunWith;
import java.io.File;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
@@ -121,7 +122,7 @@ public class BatteryUsageStatsProviderPerfTest {
}
@Test
- public void getBatteryUsageStats_accumulated() {
+ public void getBatteryUsageStats_accumulated() throws IOException {
BatteryUsageStatsQuery query = new BatteryUsageStatsQuery.Builder()
.setMaxStatsAgeMs(0)
.includePowerStateData()
@@ -155,6 +156,8 @@ public class BatteryUsageStatsProviderPerfTest {
// Verify that all iterations produce the same result
assertThat(cpuConsumedPower).isEqualTo(expectedCpuPower);
}
+ stats.close();
+
state.resumeTiming();
}
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/MultiStateStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/MultiStateStatsTest.java
index a232c0c7aec9..3b614bdb38ed 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/MultiStateStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/MultiStateStatsTest.java
@@ -143,6 +143,8 @@ public class MultiStateStatsTest {
multiStateStats.increment(new long[]{200, 200}, 5000);
+ multiStateStats.increment(null, 6000); // No-op
+
long[] stats = new long[DIMENSION_COUNT];
multiStateStats.getStats(stats, new int[]{0, BatteryConsumer.PROCESS_STATE_FOREGROUND, 0});
// (400 - 100) * 0.5 + (600 - 400) * 0.5
diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
index 32a3b7f2c9cc..22c86eb3a9b8 100644
--- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
@@ -272,6 +272,19 @@ public class PhoneWindowManagerTests {
}
@Test
+ public void powerPress_withoutDreamManagerInternal_doesNotCrash() {
+ when(mDisplayPolicy.isAwake()).thenReturn(true);
+ mDreamManagerInternal = null;
+ initPhoneWindowManager();
+
+ // Power button pressed.
+ int eventTime = 0;
+ mPhoneWindowManager.powerPress(eventTime, 1, 0);
+
+ // verify no crash
+ }
+
+ @Test
public void powerPress_hubOrDreamOrSleep_hubAvailableLocks() {
when(mDisplayPolicy.isAwake()).thenReturn(true);
mContext.getTestablePermissions().setPermission(android.Manifest.permission.DEVICE_POWER,
@@ -352,5 +365,10 @@ public class PhoneWindowManagerTests {
WindowWakeUpPolicy getWindowWakeUpPolicy() {
return mock(WindowWakeUpPolicy.class);
}
+
+ @Override
+ DreamManagerInternal getDreamManagerInternal() {
+ return mDreamManagerInternal;
+ }
}
}
diff --git a/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java
index be0c7daebb57..e62a89b17927 100644
--- a/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java
@@ -19,6 +19,7 @@ package com.android.internal.protolog;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.endsWith;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.times;
@@ -157,13 +158,15 @@ public class ProtoLogCommandHandlerTest {
cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err, new String[] { "logcat", "enable", "MY_GROUP" });
- Mockito.verify(mProtoLogConfigurationService).enableProtoLogToLogcat("MY_GROUP");
+ Mockito.verify(mProtoLogConfigurationService)
+ .enableProtoLogToLogcat(Mockito.any(), eq("MY_GROUP"));
cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err,
new String[] { "logcat", "enable", "MY_GROUP", "MY_OTHER_GROUP" });
Mockito.verify(mProtoLogConfigurationService)
- .enableProtoLogToLogcat("MY_GROUP", "MY_OTHER_GROUP");
+ .enableProtoLogToLogcat(Mockito.any(),
+ eq("MY_GROUP"), eq("MY_OTHER_GROUP"));
}
@Test
@@ -173,13 +176,15 @@ public class ProtoLogCommandHandlerTest {
cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err, new String[] { "logcat", "disable", "MY_GROUP" });
- Mockito.verify(mProtoLogConfigurationService).disableProtoLogToLogcat("MY_GROUP");
+ Mockito.verify(mProtoLogConfigurationService)
+ .disableProtoLogToLogcat(Mockito.any(), eq("MY_GROUP"));
cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err,
new String[] { "logcat", "disable", "MY_GROUP", "MY_OTHER_GROUP" });
Mockito.verify(mProtoLogConfigurationService)
- .disableProtoLogToLogcat("MY_GROUP", "MY_OTHER_GROUP");
+ .disableProtoLogToLogcat(Mockito.any(),
+ eq("MY_GROUP"), eq("MY_OTHER_GROUP"));
}
@Test
diff --git a/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
index 3be725101252..1f3f91ebf557 100644
--- a/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
@@ -62,6 +62,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.List;
/**
@@ -234,7 +235,7 @@ public class ProtoLogConfigurationServiceTest {
service.registerClient(mMockClient, args);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse();
- service.enableProtoLogToLogcat(TEST_GROUP);
+ service.enableProtoLogToLogcat(Mockito.mock(PrintWriter.class), TEST_GROUP);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue();
Mockito.verify(mMockClient).toggleLogcat(eq(true),
@@ -251,7 +252,7 @@ public class ProtoLogConfigurationServiceTest {
service.registerClient(mMockClient, args);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue();
- service.disableProtoLogToLogcat(TEST_GROUP);
+ service.disableProtoLogToLogcat(Mockito.mock(PrintWriter.class), TEST_GROUP);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse();
Mockito.verify(mMockClient).toggleLogcat(eq(false),
@@ -269,7 +270,7 @@ public class ProtoLogConfigurationServiceTest {
service.registerClient(mMockClient, args);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse();
- service.enableProtoLogToLogcat(OTHER_TEST_GROUP);
+ service.enableProtoLogToLogcat(Mockito.mock(PrintWriter.class), OTHER_TEST_GROUP);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse();
Mockito.verify(mMockClient, never()).toggleLogcat(anyBoolean(), any());
@@ -280,7 +281,7 @@ public class ProtoLogConfigurationServiceTest {
final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl();
Truth.assertThat(service.getGroups()).asList().doesNotContain(TEST_GROUP);
- service.enableProtoLogToLogcat(TEST_GROUP);
+ service.enableProtoLogToLogcat(Mockito.mock(PrintWriter.class), TEST_GROUP);
Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue();
final RegisterClientArgs args = new RegisterClientArgs();
diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java
index 1273826c8ef8..8cd89ce89e83 100644
--- a/tests/testables/src/android/testing/TestableLooper.java
+++ b/tests/testables/src/android/testing/TestableLooper.java
@@ -273,7 +273,7 @@ public class TestableLooper {
messages.add(message);
}
- // Repost all Messages back to the queuewith a new time.
+ // Repost all Messages back to the queue with a new time.
while (true) {
Message message = messages.poll();
if (message == null) {