Merge "Prevent force showing system bars for TaskView" into udc-dev
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobService.java b/apex/jobscheduler/framework/java/android/app/job/JobService.java
index f48e078..3b5f11b 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobService.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobService.java
@@ -265,7 +265,8 @@
* @see JobInfo.Builder#setRequiredNetworkType(int)
*/
public void onNetworkChanged(@NonNull JobParameters params) {
- Log.w(TAG, "onNetworkChanged() not implemented. Must override in a subclass.");
+ Log.w(TAG, "onNetworkChanged() not implemented in " + getClass().getName()
+ + ". Must override in a subclass.");
}
/**
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 2d9a99c..9bbc4a6 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -538,6 +538,7 @@
public class DevicePolicyManager {
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void acknowledgeNewUserDisclaimer();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void calculateHasIncompatibleAccounts();
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void clearOrganizationId();
method @RequiresPermission(android.Manifest.permission.CLEAR_FREEZE_PERIOD) public void clearSystemUpdatePolicyFreezePeriodRecord();
method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceNetworkLogs();
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 95e446d..021f932 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -45,6 +45,7 @@
import android.os.WorkSource;
import android.util.ArraySet;
import android.util.Pair;
+import android.util.StatsEvent;
import com.android.internal.os.TimeoutRecord;
@@ -1217,4 +1218,10 @@
*/
public abstract void notifyMediaProjectionEvent(int uid, @NonNull IBinder projectionToken,
@MediaProjectionTokenEvent int event);
+
+ /**
+ * @return The stats event for the cached apps high watermark since last pull.
+ */
+ @NonNull
+ public abstract StatsEvent getCachedAppsHighWatermarkStats(int atomTag, boolean resetAfterPull);
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4d3338b..a8a2ad1 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16825,6 +16825,23 @@
}
/**
+ * Recalculate the incompatible accounts cache.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ public void calculateHasIncompatibleAccounts() {
+ if (mService != null) {
+ try {
+ mService.calculateHasIncompatibleAccounts();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
* @return {@code true} if bypassing the device policy management role qualification is allowed
* with the current state of the device.
*
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 9b0b18a..9795cab 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -608,4 +608,6 @@
boolean isDeviceFinanced(String callerPackageName);
String getFinancedDeviceKioskRoleHolder(String callerPackageName);
+
+ void calculateHasIncompatibleAccounts();
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 74a69a6..307f306 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -12349,7 +12349,9 @@
null, new String[] { getType() },
new ClipData.Item(text, htmlText, null, stream));
setClipData(clipData);
- addFlags(FLAG_GRANT_READ_URI_PERMISSION);
+ if (stream != null) {
+ addFlags(FLAG_GRANT_READ_URI_PERMISSION);
+ }
return true;
}
} catch (ClassCastException e) {
@@ -12388,7 +12390,9 @@
}
setClipData(clipData);
- addFlags(FLAG_GRANT_READ_URI_PERMISSION);
+ if (streams != null) {
+ addFlags(FLAG_GRANT_READ_URI_PERMISSION);
+ }
return true;
}
} catch (ClassCastException e) {
diff --git a/core/java/android/content/res/FontScaleConverterFactory.java b/core/java/android/content/res/FontScaleConverterFactory.java
index 6b09c30..5eb6526 100644
--- a/core/java/android/content/res/FontScaleConverterFactory.java
+++ b/core/java/android/content/res/FontScaleConverterFactory.java
@@ -34,6 +34,8 @@
@VisibleForTesting
static final SparseArray<FontScaleConverter> LOOKUP_TABLES = new SparseArray<>();
+ private static float sMinScaleBeforeCurvesApplied = 1.05f;
+
static {
// These were generated by frameworks/base/tools/fonts/font-scaling-array-generator.js and
// manually tweaked for optimum readability.
@@ -82,11 +84,30 @@
new float[] { 16f, 20f, 24f, 26f, 30f, 34f, 36f, 38f, 100})
);
+ sMinScaleBeforeCurvesApplied = getScaleFromKey(LOOKUP_TABLES.keyAt(0)) - 0.02f;
+ if (sMinScaleBeforeCurvesApplied <= 1.0f) {
+ throw new IllegalStateException(
+ "You should only apply non-linear scaling to font scales > 1"
+ );
+ }
}
private FontScaleConverterFactory() {}
/**
+ * Returns true if non-linear font scaling curves would be in effect for the given scale, false
+ * if the scaling would follow a linear curve or for no scaling.
+ *
+ * <p>Example usage:
+ * <code>isNonLinearFontScalingActive(getResources().getConfiguration().fontScale)</code>
+ *
+ * @hide
+ */
+ public static boolean isNonLinearFontScalingActive(float fontScale) {
+ return fontScale >= sMinScaleBeforeCurvesApplied;
+ }
+
+ /**
* Finds a matching FontScaleConverter for the given fontScale factor.
*
* @param fontScale the scale factor, usually from {@link Configuration#fontScale}.
@@ -97,10 +118,7 @@
*/
@Nullable
public static FontScaleConverter forScale(float fontScale) {
- if (fontScale <= 1) {
- // We don't need non-linear curves for shrinking text or for 100%.
- // Also, fontScale==0 should not have a curve either.
- // And ignore negative font scales; that's just silly.
+ if (!isNonLinearFontScalingActive(fontScale)) {
return null;
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 72a3f6c..b453304 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -53,12 +53,16 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import libcore.util.EmptyArray;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
+import java.util.function.Predicate;
/**
@@ -86,9 +90,6 @@
@GuardedBy("mLock")
private final WeakDisplayCache mDisplayCache = new WeakDisplayCache();
- @GuardedBy("mLock")
- private final ArrayList<Display> mTempDisplays = new ArrayList<Display>();
-
/**
* Broadcast receiver that indicates when the Wifi display status changes.
* <p>
@@ -627,9 +628,7 @@
* @return The display object, or null if there is no valid display with the given id.
*/
public Display getDisplay(int displayId) {
- synchronized (mLock) {
- return getOrCreateDisplayLocked(displayId, false /*assumeValid*/);
- }
+ return getOrCreateDisplay(displayId, false /*assumeValid*/);
}
/**
@@ -661,75 +660,67 @@
boolean includeDisabled = (category != null
&& category.equals(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED));
final int[] displayIds = mGlobal.getDisplayIds(includeDisabled);
- synchronized (mLock) {
- try {
- if (DISPLAY_CATEGORY_PRESENTATION.equals(category)) {
- addDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI,
- Display.FLAG_PRESENTATION);
- addDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_EXTERNAL,
- Display.FLAG_PRESENTATION);
- addDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY,
- Display.FLAG_PRESENTATION);
- addDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL,
- Display.FLAG_PRESENTATION);
- addDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_INTERNAL,
- Display.FLAG_PRESENTATION);
- } else if (DISPLAY_CATEGORY_REAR.equals(category)) {
- addDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_INTERNAL,
- Display.FLAG_REAR);
- } else if (category == null
- || DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED.equals(category)) {
- addAllDisplaysLocked(mTempDisplays, displayIds);
- }
- return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
- } finally {
- mTempDisplays.clear();
- }
+ if (DISPLAY_CATEGORY_PRESENTATION.equals(category)) {
+ return getDisplays(displayIds, DisplayManager::isPresentationDisplay);
+ } else if (DISPLAY_CATEGORY_REAR.equals(category)) {
+ return getDisplays(displayIds, DisplayManager::isRearDisplay);
+ } else if (category == null || DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED.equals(category)) {
+ return getDisplays(displayIds, Objects::nonNull);
}
+ return (Display[]) EmptyArray.OBJECT;
}
- @GuardedBy("mLock")
- private void addAllDisplaysLocked(ArrayList<Display> displays, int[] displayIds) {
- for (int i = 0; i < displayIds.length; i++) {
- Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
- if (display != null) {
- displays.add(display);
- }
- }
- }
-
- @GuardedBy("mLock")
- private void addDisplaysLocked(
- ArrayList<Display> displays, int[] displayIds, int matchType, int flagMask) {
+ private Display[] getDisplays(int[] displayIds, Predicate<Display> predicate) {
+ ArrayList<Display> tmpDisplays = new ArrayList<>();
for (int displayId : displayIds) {
- if (displayId == DEFAULT_DISPLAY) {
- continue;
+ Display display = getOrCreateDisplay(displayId, /*assumeValid=*/true);
+ if (predicate.test(display)) {
+ tmpDisplays.add(display);
}
+ }
+ return tmpDisplays.toArray(new Display[tmpDisplays.size()]);
+ }
- Display display = getOrCreateDisplayLocked(displayId, /* assumeValid= */ true);
- if (display != null
- && (display.getFlags() & flagMask) == flagMask
- && display.getType() == matchType) {
- displays.add(display);
- }
+ private static boolean isPresentationDisplay(@Nullable Display display) {
+ if (display == null || (display.getDisplayId() == DEFAULT_DISPLAY)
+ || (display.getFlags() & Display.FLAG_PRESENTATION) == 0) {
+ return false;
+ }
+ switch (display.getType()) {
+ case Display.TYPE_INTERNAL:
+ case Display.TYPE_EXTERNAL:
+ case Display.TYPE_WIFI:
+ case Display.TYPE_OVERLAY:
+ case Display.TYPE_VIRTUAL:
+ return true;
+ default:
+ return false;
}
}
- @GuardedBy("mLock")
- private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) {
- Display display = mDisplayCache.get(displayId);
- if (display == null) {
- // TODO: We cannot currently provide any override configurations for metrics on displays
- // other than the display the context is associated with.
- final Resources resources = mContext.getDisplayId() == displayId
- ? mContext.getResources() : null;
+ private static boolean isRearDisplay(@Nullable Display display) {
+ return display != null && display.getDisplayId() != DEFAULT_DISPLAY
+ && display.getType() == Display.TYPE_INTERNAL
+ && (display.getFlags() & Display.FLAG_REAR) != 0;
+ }
- display = mGlobal.getCompatibleDisplay(displayId, resources);
- if (display != null) {
- mDisplayCache.put(display);
+ private Display getOrCreateDisplay(int displayId, boolean assumeValid) {
+ Display display;
+ synchronized (mLock) {
+ display = mDisplayCache.get(displayId);
+ if (display == null) {
+ // TODO: We cannot currently provide any override configurations for metrics on
+ // displays other than the display the context is associated with.
+ final Resources resources = mContext.getDisplayId() == displayId
+ ? mContext.getResources() : null;
+
+ display = mGlobal.getCompatibleDisplay(displayId, resources);
+ if (display != null) {
+ mDisplayCache.put(display);
+ }
+ } else if (!assumeValid && !display.isValid()) {
+ display = null;
}
- } else if (!assumeValid && !display.isValid()) {
- display = null;
}
return display;
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 2fec02f..a0cceae 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -39,7 +39,6 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Vibrator;
-import android.sysprop.InputProperties;
import android.util.Log;
import android.view.Display;
import android.view.InputDevice;
@@ -1038,9 +1037,7 @@
*/
public boolean isStylusPointerIconEnabled() {
if (mIsStylusPointerIconEnabled == null) {
- mIsStylusPointerIconEnabled = mContext.getResources()
- .getBoolean(com.android.internal.R.bool.config_enableStylusPointerIcon)
- || InputProperties.force_enable_stylus_pointer_icon().orElse(false);
+ mIsStylusPointerIconEnabled = InputSettings.isStylusPointerIconEnabled(mContext);
}
return mIsStylusPointerIconEnabled;
}
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index 5462171..c0877d3 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -1252,7 +1252,7 @@
/**
* @see InputManager#requestPointerCapture(IBinder, boolean)
*/
- void requestPointerCapture(IBinder windowToken, boolean enable) {
+ public void requestPointerCapture(IBinder windowToken, boolean enable) {
try {
mIm.requestPointerCapture(windowToken, enable);
} catch (RemoteException ex) {
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index cdf9ea5..6cd32ff 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -25,6 +25,7 @@
import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;
+import android.sysprop.InputProperties;
/**
* InputSettings encapsulates reading and writing settings related to input
@@ -316,4 +317,15 @@
Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE, enabled ? 1 : 0,
UserHandle.USER_CURRENT);
}
+
+ /**
+ * Whether a pointer icon will be shown over the location of a
+ * stylus pointer.
+ * @hide
+ */
+ public static boolean isStylusPointerIconEnabled(@NonNull Context context) {
+ return context.getResources()
+ .getBoolean(com.android.internal.R.bool.config_enableStylusPointerIcon)
+ || InputProperties.force_enable_stylus_pointer_icon().orElse(false);
+ }
}
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index b93e338..330a9fc 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -385,10 +385,22 @@
*
* @return The complex unit type.
*/
- public int getComplexUnit()
- {
- return COMPLEX_UNIT_MASK & (data>>TypedValue.COMPLEX_UNIT_SHIFT);
- }
+ public int getComplexUnit() {
+ return getUnitFromComplexDimension(data);
+ }
+
+ /**
+ * Return the complex unit type for the given complex dimension. For example, a dimen type
+ * with value 12sp will return {@link #COMPLEX_UNIT_SP}. Use with values created with {@link
+ * #createComplexDimension(int, int)} etc.
+ *
+ * @return The complex unit type.
+ *
+ * @hide
+ */
+ public static int getUnitFromComplexDimension(int complexDimension) {
+ return COMPLEX_UNIT_MASK & (complexDimension >> TypedValue.COMPLEX_UNIT_SHIFT);
+ }
/**
* Converts an unpacked complex data value holding a dimension to its final floating point pixel
diff --git a/core/java/android/view/InputMonitor.java b/core/java/android/view/InputMonitor.java
index 8801fe0..4996f5a 100644
--- a/core/java/android/view/InputMonitor.java
+++ b/core/java/android/view/InputMonitor.java
@@ -43,7 +43,8 @@
private final InputChannel mInputChannel;
@NonNull
private final IInputMonitorHost mHost;
-
+ @NonNull
+ private final SurfaceControl mSurface;
/**
* Takes all of the current pointer events streams that are currently being sent to this
@@ -70,6 +71,7 @@
*/
public void dispose() {
mInputChannel.dispose();
+ mSurface.release();
try {
mHost.dispose();
} catch (RemoteException e) {
@@ -95,13 +97,17 @@
@DataClass.Generated.Member
public InputMonitor(
@NonNull InputChannel inputChannel,
- @NonNull IInputMonitorHost host) {
+ @NonNull IInputMonitorHost host,
+ @NonNull SurfaceControl surface) {
this.mInputChannel = inputChannel;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mInputChannel);
this.mHost = host;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mHost);
+ this.mSurface = surface;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mSurface);
// onConstructed(); // You can define this method to get a callback
}
@@ -116,6 +122,11 @@
return mHost;
}
+ @DataClass.Generated.Member
+ public @NonNull SurfaceControl getSurface() {
+ return mSurface;
+ }
+
@Override
@DataClass.Generated.Member
public String toString() {
@@ -124,7 +135,8 @@
return "InputMonitor { " +
"inputChannel = " + mInputChannel + ", " +
- "host = " + mHost +
+ "host = " + mHost + ", " +
+ "surface = " + mSurface +
" }";
}
@@ -136,6 +148,7 @@
dest.writeTypedObject(mInputChannel, flags);
dest.writeStrongInterface(mHost);
+ dest.writeTypedObject(mSurface, flags);
}
@Override
@@ -151,6 +164,7 @@
InputChannel inputChannel = (InputChannel) in.readTypedObject(InputChannel.CREATOR);
IInputMonitorHost host = IInputMonitorHost.Stub.asInterface(in.readStrongBinder());
+ SurfaceControl surface = (SurfaceControl) in.readTypedObject(SurfaceControl.CREATOR);
this.mInputChannel = inputChannel;
com.android.internal.util.AnnotationValidations.validate(
@@ -158,6 +172,9 @@
this.mHost = host;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mHost);
+ this.mSurface = surface;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mSurface);
// onConstructed(); // You can define this method to get a callback
}
@@ -177,10 +194,10 @@
};
@DataClass.Generated(
- time = 1637697281750L,
+ time = 1679692514588L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/InputMonitor.java",
- inputSignatures = "private static final java.lang.String TAG\nprivate static final boolean DEBUG\nprivate final @android.annotation.NonNull android.view.InputChannel mInputChannel\nprivate final @android.annotation.NonNull android.view.IInputMonitorHost mHost\npublic void pilferPointers()\npublic void dispose()\nclass InputMonitor extends java.lang.Object implements [android.os.Parcelable]\[email protected](genToString=true)")
+ inputSignatures = "private static final java.lang.String TAG\nprivate static final boolean DEBUG\nprivate final @android.annotation.NonNull android.view.InputChannel mInputChannel\nprivate final @android.annotation.NonNull android.view.IInputMonitorHost mHost\nprivate final @android.annotation.NonNull android.view.SurfaceControl mSurface\npublic void pilferPointers()\npublic void dispose()\nclass InputMonitor extends java.lang.Object implements [android.os.Parcelable]\[email protected](genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index bd6224b..d987217 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -410,6 +410,13 @@
}
/**
+ * @hide
+ */
+ public @NonNull AttachedSurfaceControl getRootSurfaceControl() {
+ return mViewRoot;
+ }
+
+ /**
* Set the root view of the SurfaceControlViewHost. This view will render in to
* the SurfaceControl, and receive input based on the SurfaceControls positioning on
* screen. It will be laid as if it were in a window of the passed in width and height.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 86e7fb0..2b29e78 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -133,7 +133,9 @@
import android.graphics.drawable.GradientDrawable;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
-import android.hardware.input.InputManager;
+import android.hardware.display.DisplayManagerGlobal;
+import android.hardware.input.InputManagerGlobal;
+import android.hardware.input.InputSettings;
import android.media.AudioManager;
import android.os.Binder;
import android.os.Build;
@@ -443,9 +445,7 @@
@UnsupportedAppUsage
final IWindowSession mWindowSession;
@NonNull Display mDisplay;
- final DisplayManager mDisplayManager;
final String mBasePackageName;
- final InputManager mInputManager;
final int[] mTmpLocation = new int[2];
@@ -550,6 +550,9 @@
// Whether to draw this surface as DISPLAY_DECORATION.
boolean mDisplayDecorationCached = false;
+ // Is the stylus pointer icon enabled
+ private final boolean mIsStylusPointerIconEnabled;
+
/**
* Update the Choreographer's FrameInfo object with the timing information for the current
* ViewRootImpl instance. Erase the data in the current ViewFrameInfo to prepare for the next
@@ -994,14 +997,14 @@
mFallbackEventHandler = new PhoneFallbackEventHandler(context);
// TODO(b/222696368): remove getSfInstance usage and use vsyncId for transactions
mChoreographer = Choreographer.getInstance();
- mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
- mInputManager = context.getSystemService(InputManager.class);
mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this));
mHandwritingInitiator = new HandwritingInitiator(
mViewConfiguration,
mContext.getSystemService(InputMethodManager.class));
mViewBoundsSandboxingEnabled = getViewBoundsSandboxingEnabled();
+ mIsStylusPointerIconEnabled =
+ InputSettings.isStylusPointerIconEnabled(mContext);
String processorOverrideName = context.getResources().getString(
R.string.config_inputEventCompatProcessorOverrideClassName);
@@ -1488,7 +1491,14 @@
mAccessibilityInteractionConnectionManager, mHandler);
mAccessibilityManager.addHighTextContrastStateChangeListener(
mHighContrastTextManager, mHandler);
- mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
+ DisplayManagerGlobal
+ .getInstance()
+ .registerDisplayListener(
+ mDisplayListener,
+ mHandler,
+ DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+ | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+ | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
}
/**
@@ -1499,7 +1509,9 @@
mAccessibilityInteractionConnectionManager);
mAccessibilityManager.removeHighTextContrastStateChangeListener(
mHighContrastTextManager);
- mDisplayManager.unregisterDisplayListener(mDisplayListener);
+ DisplayManagerGlobal
+ .getInstance()
+ .unregisterDisplayListener(mDisplayListener);
}
private void setTag() {
@@ -5382,7 +5394,9 @@
Log.e(mTag, "No input channel to request Pointer Capture.");
return;
}
- mInputManager.requestPointerCapture(inputToken, enabled);
+ InputManagerGlobal
+ .getInstance()
+ .requestPointerCapture(inputToken, enabled);
}
private void handlePointerCaptureChanged(boolean hasCapture) {
@@ -6947,7 +6961,7 @@
}
final boolean needsStylusPointerIcon = event.isStylusPointer()
&& event.isHoverEvent()
- && mInputManager.isStylusPointerIconEnabled();
+ && mIsStylusPointerIconEnabled;
if (needsStylusPointerIcon || event.isFromSource(InputDevice.SOURCE_MOUSE)) {
if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
|| event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
@@ -7018,8 +7032,7 @@
}
PointerIcon pointerIcon = null;
-
- if (event.isStylusPointer() && mInputManager.isStylusPointerIconEnabled()) {
+ if (event.isStylusPointer() && mIsStylusPointerIconEnabled) {
pointerIcon = mHandwritingInitiator.onResolvePointerIcon(mContext, event);
}
@@ -7034,14 +7047,18 @@
mPointerIconType = pointerType;
mCustomPointerIcon = null;
if (mPointerIconType != PointerIcon.TYPE_CUSTOM) {
- mInputManager.setPointerIconType(pointerType);
+ InputManagerGlobal
+ .getInstance()
+ .setPointerIconType(pointerType);
return true;
}
}
if (mPointerIconType == PointerIcon.TYPE_CUSTOM &&
!pointerIcon.equals(mCustomPointerIcon)) {
mCustomPointerIcon = pointerIcon;
- mInputManager.setCustomPointerIcon(mCustomPointerIcon);
+ InputManagerGlobal
+ .getInstance()
+ .setCustomPointerIcon(mCustomPointerIcon);
}
return true;
}
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index a5e7086..b65c1a1 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -845,11 +845,7 @@
// Calling overScrollBy will call onOverScrolled, which
// calls onScrollChanged if applicable.
- if (overScrollBy(0, deltaY, 0, mScrollY, 0, range, 0, mOverscrollDistance, true)
- && !hasNestedScrollingParent()) {
- // Break our velocity if we hit a scroll barrier.
- mVelocityTracker.clear();
- }
+ overScrollBy(0, deltaY, 0, mScrollY, 0, range, 0, mOverscrollDistance, true);
final int scrolledDeltaY = mScrollY - oldY;
final int unconsumedY = deltaY - scrolledDeltaY;
@@ -894,6 +890,7 @@
mActivePointerId = INVALID_POINTER;
endDrag();
+ velocityTracker.clear();
}
break;
case MotionEvent.ACTION_CANCEL:
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 67c9f8c..3fbb505 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -62,6 +62,7 @@
import android.content.res.ColorStateList;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
+import android.content.res.FontScaleConverterFactory;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -867,6 +868,14 @@
@UnsupportedAppUsage
private float mSpacingAdd = 0.0f;
+ /**
+ * Remembers what line height was set to originally, before we broke it down into raw pixels.
+ *
+ * <p>This is stored as a complex dimension with both value and unit packed into one field!
+ * {@see TypedValue}
+ */
+ private int mLineHeightComplexDimen;
+
private int mBreakStrategy;
private int mHyphenationFrequency;
private int mJustificationMode;
@@ -1233,7 +1242,8 @@
defStyleAttr, defStyleRes);
int firstBaselineToTopHeight = -1;
int lastBaselineToBottomHeight = -1;
- int lineHeight = -1;
+ float lineHeight = -1f;
+ int lineHeightUnit = -1;
readTextAppearance(context, a, attributes, true /* styleArray */);
@@ -1583,7 +1593,13 @@
break;
case com.android.internal.R.styleable.TextView_lineHeight:
- lineHeight = a.getDimensionPixelSize(attr, -1);
+ TypedValue peekValue = a.peekValue(attr);
+ if (peekValue != null && peekValue.type == TypedValue.TYPE_DIMENSION) {
+ lineHeightUnit = peekValue.getComplexUnit();
+ lineHeight = TypedValue.complexToFloat(peekValue.data);
+ } else {
+ lineHeight = a.getDimensionPixelSize(attr, -1);
+ }
break;
}
}
@@ -1936,7 +1952,11 @@
setLastBaselineToBottomHeight(lastBaselineToBottomHeight);
}
if (lineHeight >= 0) {
- setLineHeight(lineHeight);
+ if (lineHeightUnit == -1) {
+ setLineHeightPx(lineHeight);
+ } else {
+ setLineHeight(lineHeightUnit, lineHeight);
+ }
}
}
@@ -4629,6 +4649,7 @@
if (size != mTextPaint.getTextSize()) {
mTextPaint.setTextSize(size);
+ maybeRecalculateLineHeight();
if (shouldRequestLayout && mLayout != null) {
// Do not auto-size right after setting the text size.
mNeedsAutoSizeText = false;
@@ -6214,6 +6235,9 @@
if (lineHeight != fontHeight) {
// Set lineSpacingExtra by the difference of lineSpacing with lineHeight
setLineSpacing(lineHeight - fontHeight, 1f);
+
+ mLineHeightComplexDimen =
+ TypedValue.createComplexDimension(lineHeight, TypedValue.COMPLEX_UNIT_PX);
}
}
@@ -6236,8 +6260,54 @@
@TypedValue.ComplexDimensionUnit int unit,
@FloatRange(from = 0) float lineHeight
) {
- setLineHeightPx(
- TypedValue.applyDimension(unit, lineHeight, getDisplayMetricsOrSystem()));
+ var metrics = getDisplayMetricsOrSystem();
+ // We can avoid the recalculation if we know non-linear font scaling isn't being used
+ // (an optimization for the majority case).
+ // We also don't try to do the recalculation unless both textSize and lineHeight are in SP.
+ if (!FontScaleConverterFactory.isNonLinearFontScalingActive(
+ getResources().getConfiguration().fontScale)
+ || unit != TypedValue.COMPLEX_UNIT_SP
+ || mTextSizeUnit != TypedValue.COMPLEX_UNIT_SP
+ ) {
+ setLineHeightPx(TypedValue.applyDimension(unit, lineHeight, metrics));
+
+ // Do this last so it overwrites what setLineHeightPx() sets it to.
+ mLineHeightComplexDimen = TypedValue.createComplexDimension(lineHeight, unit);
+ return;
+ }
+
+ // Recalculate a proportional line height when non-linear font scaling is in effect.
+ // Otherwise, a desired 2x line height at font scale 1.0 will not be 2x at font scale 2.0,
+ // due to non-linear font scaling compressing higher SP sizes. See b/273326061 for details.
+ // We know they are using SP units for both the text size and the line height
+ // at this point, so determine the ratio between them. This is the *intended* line spacing
+ // multiplier if font scale == 1.0. We can then determine what the pixel value for the line
+ // height would be if we preserved proportions.
+ var textSizePx = getTextSize();
+ var textSizeSp = TypedValue.convertPixelsToDimension(
+ TypedValue.COMPLEX_UNIT_SP,
+ textSizePx,
+ metrics
+ );
+ var ratio = lineHeight / textSizeSp;
+ setLineHeightPx(textSizePx * ratio);
+
+ // Do this last so it overwrites what setLineHeightPx() sets it to.
+ mLineHeightComplexDimen = TypedValue.createComplexDimension(lineHeight, unit);
+ }
+
+ private void maybeRecalculateLineHeight() {
+ if (mLineHeightComplexDimen == 0) {
+ return;
+ }
+ int unit = TypedValue.getUnitFromComplexDimension(mLineHeightComplexDimen);
+ if (unit != TypedValue.COMPLEX_UNIT_SP) {
+ // The lineHeight was never supplied in SP, so we didn't do any fancy recalculations
+ // in setLineHeight(). We don't need to recalculate.
+ return;
+ }
+
+ setLineHeight(unit, TypedValue.complexToFloat(mLineHeightComplexDimen));
}
/**
diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
index 134a917..efaedd1 100644
--- a/core/java/com/android/internal/policy/DecorContext.java
+++ b/core/java/com/android/internal/policy/DecorContext.java
@@ -82,13 +82,6 @@
}
return mContentCaptureManager;
}
- // TODO(b/154191411): Try to revisit this issue in S.
- // We use application to get DisplayManager here because ViewRootImpl holds reference of
- // DisplayManager and implicitly holds reference of mContext, which makes activity cannot
- // be GC'd even after destroyed if mContext is an activity object.
- if (Context.DISPLAY_SERVICE.equals(name)) {
- return super.getSystemService(name);
- }
// LayoutInflater and WallpaperManagerService should also be obtained from visual context
// instead of base context.
return (context != null) ? context.getSystemService(name) : super.getSystemService(name);
diff --git a/core/java/com/android/internal/util/QuickSelect.java b/core/java/com/android/internal/util/QuickSelect.java
new file mode 100644
index 0000000..17739c9
--- /dev/null
+++ b/core/java/com/android/internal/util/QuickSelect.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2023 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.internal.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * An implementation of the quick selection algorithm as described in
+ * http://en.wikipedia.org/wiki/Quickselect.
+ *
+ * @hide
+ */
+public final class QuickSelect {
+ private static <T> int selectImpl(@NonNull List<T> list, int left, int right, int k,
+ @NonNull Comparator<? super T> comparator) {
+ while (true) {
+ if (left == right) {
+ return left;
+ }
+ final int pivotIndex = partition(list, left, right, (left + right) >> 1, comparator);
+ if (k == pivotIndex) {
+ return k;
+ } else if (k < pivotIndex) {
+ right = pivotIndex - 1;
+ } else {
+ left = pivotIndex + 1;
+ }
+ }
+ }
+
+ private static int selectImpl(@NonNull int[] array, int left, int right, int k) {
+ while (true) {
+ if (left == right) {
+ return left;
+ }
+ final int pivotIndex = partition(array, left, right, (left + right) >> 1);
+ if (k == pivotIndex) {
+ return k;
+ } else if (k < pivotIndex) {
+ right = pivotIndex - 1;
+ } else {
+ left = pivotIndex + 1;
+ }
+ }
+ }
+
+ private static int selectImpl(@NonNull long[] array, int left, int right, int k) {
+ while (true) {
+ if (left == right) {
+ return left;
+ }
+ final int pivotIndex = partition(array, left, right, (left + right) >> 1);
+ if (k == pivotIndex) {
+ return k;
+ } else if (k < pivotIndex) {
+ right = pivotIndex - 1;
+ } else {
+ left = pivotIndex + 1;
+ }
+ }
+ }
+
+ private static <T> int selectImpl(@NonNull T[] array, int left, int right, int k,
+ @NonNull Comparator<? super T> comparator) {
+ while (true) {
+ if (left == right) {
+ return left;
+ }
+ final int pivotIndex = partition(array, left, right, (left + right) >> 1, comparator);
+ if (k == pivotIndex) {
+ return k;
+ } else if (k < pivotIndex) {
+ right = pivotIndex - 1;
+ } else {
+ left = pivotIndex + 1;
+ }
+ }
+ }
+
+ private static <T> int partition(@NonNull List<T> list, int left, int right, int pivotIndex,
+ @NonNull Comparator<? super T> comparator) {
+ final T pivotValue = list.get(pivotIndex);
+ swap(list, right, pivotIndex);
+ int storeIndex = left;
+ for (int i = left; i < right; i++) {
+ if (comparator.compare(list.get(i), pivotValue) < 0) {
+ swap(list, storeIndex, i);
+ storeIndex++;
+ }
+ }
+ swap(list, right, storeIndex);
+ return storeIndex;
+ }
+
+ private static int partition(@NonNull int[] array, int left, int right, int pivotIndex) {
+ final int pivotValue = array[pivotIndex];
+ swap(array, right, pivotIndex);
+ int storeIndex = left;
+ for (int i = left; i < right; i++) {
+ if (array[i] < pivotValue) {
+ swap(array, storeIndex, i);
+ storeIndex++;
+ }
+ }
+ swap(array, right, storeIndex);
+ return storeIndex;
+ }
+
+ private static int partition(@NonNull long[] array, int left, int right, int pivotIndex) {
+ final long pivotValue = array[pivotIndex];
+ swap(array, right, pivotIndex);
+ int storeIndex = left;
+ for (int i = left; i < right; i++) {
+ if (array[i] < pivotValue) {
+ swap(array, storeIndex, i);
+ storeIndex++;
+ }
+ }
+ swap(array, right, storeIndex);
+ return storeIndex;
+ }
+
+ private static <T> int partition(@NonNull T[] array, int left, int right, int pivotIndex,
+ @NonNull Comparator<? super T> comparator) {
+ final T pivotValue = array[pivotIndex];
+ swap(array, right, pivotIndex);
+ int storeIndex = left;
+ for (int i = left; i < right; i++) {
+ if (comparator.compare(array[i], pivotValue) < 0) {
+ swap(array, storeIndex, i);
+ storeIndex++;
+ }
+ }
+ swap(array, right, storeIndex);
+ return storeIndex;
+ }
+
+ private static <T> void swap(@NonNull List<T> list, int left, int right) {
+ final T tmp = list.get(left);
+ list.set(left, list.get(right));
+ list.set(right, tmp);
+ }
+
+ private static void swap(@NonNull int[] array, int left, int right) {
+ final int tmp = array[left];
+ array[left] = array[right];
+ array[right] = tmp;
+ }
+
+ private static void swap(@NonNull long[] array, int left, int right) {
+ final long tmp = array[left];
+ array[left] = array[right];
+ array[right] = tmp;
+ }
+
+ private static <T> void swap(@NonNull T[] array, int left, int right) {
+ final T tmp = array[left];
+ array[left] = array[right];
+ array[right] = tmp;
+ }
+
+ /**
+ * Return the kth(0-based) smallest element from the given unsorted list.
+ *
+ * @param list The input list, it <b>will</b> be modified by the algorithm here.
+ * @param start The start offset of the list, inclusive.
+ * @param length The length of the sub list to be searched in.
+ * @param k The 0-based index.
+ * @param comparator The comparator which knows how to compare the elements in the list.
+ * @return The kth smallest element from the given list,
+ * or IllegalArgumentException will be thrown if not found.
+ */
+ @Nullable
+ public static <T> T select(@NonNull List<T> list, int start, int length, int k,
+ @NonNull Comparator<? super T> comparator) {
+ if (list == null || start < 0 || length <= 0 || list.size() < start + length
+ || k < 0 || length <= k) {
+ throw new IllegalArgumentException();
+ }
+ return list.get(selectImpl(list, start, start + length - 1, k + start, comparator));
+ }
+
+ /**
+ * Return the kth(0-based) smallest element from the given unsorted array.
+ *
+ * @param array The input array, it <b>will</b> be modified by the algorithm here.
+ * @param start The start offset of the array, inclusive.
+ * @param length The length of the sub array to be searched in.
+ * @param k The 0-based index to search for.
+ * @return The kth smallest element from the given array,
+ * or IllegalArgumentException will be thrown if not found.
+ */
+ public static int select(@NonNull int[] array, int start, int length, int k) {
+ if (array == null || start < 0 || length <= 0 || array.length < start + length
+ || k < 0 || length <= k) {
+ throw new IllegalArgumentException();
+ }
+ return array[selectImpl(array, start, start + length - 1, k + start)];
+ }
+
+ /**
+ * Return the kth(0-based) smallest element from the given unsorted array.
+ *
+ * @param array The input array, it <b>will</b> be modified by the algorithm here.
+ * @param start The start offset of the array, inclusive.
+ * @param length The length of the sub array to be searched in.
+ * @param k The 0-based index to search for.
+ * @return The kth smallest element from the given array,
+ * or IllegalArgumentException will be thrown if not found.
+ */
+ public static long select(@NonNull long[] array, int start, int length, int k) {
+ if (array == null || start < 0 || length <= 0 || array.length < start + length
+ || k < 0 || length <= k) {
+ throw new IllegalArgumentException();
+ }
+ return array[selectImpl(array, start, start + length - 1, k + start)];
+ }
+
+ /**
+ * Return the kth(0-based) smallest element from the given unsorted array.
+ *
+ * @param array The input array, it <b>will</b> be modified by the algorithm here.
+ * @param start The start offset of the array, inclusive.
+ * @param length The length of the sub array to be searched in.
+ * @param k The 0-based index to search for.
+ * @param comparator The comparator which knows how to compare the elements in the list.
+ * @return The kth smallest element from the given array,
+ * or IllegalArgumentException will be thrown if not found.
+ */
+ public static <T> T select(@NonNull T[] array, int start, int length, int k,
+ @NonNull Comparator<? super T> comparator) {
+ if (array == null || start < 0 || length <= 0 || array.length < start + length
+ || k < 0 || length <= k) {
+ throw new IllegalArgumentException();
+ }
+ return array[selectImpl(array, start, start + length - 1, k + start, comparator)];
+ }
+}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 6bec6bc..42d6896 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -334,7 +334,7 @@
"libtimeinstate",
"server_configurable_flags",
"libimage_io",
- "libjpegrecoverymap",
+ "libultrahdr",
],
export_shared_lib_headers: [
// our headers include libnativewindow's public headers
@@ -393,7 +393,7 @@
"libimage_io",
"libjpegdecoder",
"libjpegencoder",
- "libjpegrecoverymap",
+ "libultrahdr",
],
},
host_linux: {
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index bb3089b..325ebbe 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -458,6 +458,7 @@
optional float global_scale = 44;
repeated .android.graphics.RectProto keep_clear_areas = 45;
repeated .android.graphics.RectProto unrestricted_keep_clear_areas = 46;
+ repeated .android.view.InsetsSourceProto mergedLocalInsetsSources = 47;
}
message IdentifierProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 05b38a5..e62477f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1466,6 +1466,9 @@
<!-- Allows an application to initiate a phone call without going through
the Dialer user interface for the user to confirm the call.
+ <p>
+ <em>Note: An app holding this permission can also call carrier MMI codes to change settings
+ such as call forwarding or call waiting preferences.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.CALL_PHONE"
@@ -2917,6 +2920,14 @@
<permission android:name="android.permission.BIND_SATELLITE_SERVICE"
android:protectionLevel="signature|privileged|vendorPrivileged" />
+ <!-- Must be required by a SatelliteGatewayService to ensure that only the
+ system can bind to it.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_SATELLITE_GATEWAY_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- Must be required by a telephony data service to ensure that only the
system can bind to it.
<p>Protection level: signature
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index fab7609..a57a051 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -125,6 +125,10 @@
<string name="config_satellite_service_package" translatable="false"></string>
<java-symbol type="string" name="config_satellite_service_package" />
+ <!-- Telephony satellite gateway service package name to bind to by default. -->
+ <string name="config_satellite_gateway_service_package" translatable="false"></string>
+ <java-symbol type="string" name="config_satellite_gateway_service_package" />
+
<!-- Telephony pointing UI package name to be launched. -->
<string name="config_pointing_ui_package" translatable="false"></string>
<java-symbol type="string" name="config_pointing_ui_package" />
@@ -142,10 +146,6 @@
<bool name="config_enhanced_iwlan_handover_check">true</bool>
<java-symbol type="bool" name="config_enhanced_iwlan_handover_check" />
- <!-- Whether using the new SubscriptionManagerService or the old SubscriptionController -->
- <bool name="config_using_subscription_manager_service">true</bool>
- <java-symbol type="bool" name="config_using_subscription_manager_service" />
-
<!-- Whether asynchronously update the subscription database or not. Async mode increases
the performance, but sync mode reduces the chance of database/cache out-of-sync. -->
<bool name="config_subscription_database_async_update">true</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ccd0dcc..b0932d6 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1452,7 +1452,8 @@
without your intervention. This may result in unexpected charges or calls.
Note that this doesn\'t allow the app to call emergency numbers.
Malicious apps may cost you money by making calls without your
- confirmation.</string>
+ confirmation, or dial carrier codes which cause incoming calls to be
+ automatically forwarded to another number.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_accessImsCallService">access IMS call service</string>
@@ -5907,9 +5908,9 @@
<string name="resolver_no_personal_apps_available">No personal apps</string>
<!-- Dialog title. User must choose between opening content in a cross-profile app or same-profile browser. [CHAR LIMIT=NONE] -->
- <string name="miniresolver_open_in_personal">Open <xliff:g id="app" example="YouTube">%s</xliff:g> in your personal profile?</string>
+ <string name="miniresolver_open_in_personal">Open personal <xliff:g id="app" example="YouTube">%s</xliff:g></string>
<!-- Dialog title. User must choose between opening content in a cross-profile app or same-profile browser. [CHAR LIMIT=NONE] -->
- <string name="miniresolver_open_in_work">Open <xliff:g id="app" example="YouTube">%s</xliff:g> in your work profile?</string>
+ <string name="miniresolver_open_in_work">Open work <xliff:g id="app" example="YouTube">%s</xliff:g></string>
<!-- Button option. Open the link in the personal browser. [CHAR LIMIT=NONE] -->
<string name="miniresolver_use_personal_browser">Use personal browser</string>
<!-- Button option. Open the link in the work browser. [CHAR LIMIT=NONE] -->
diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
index a0d8dcf..ba6c8fa 100644
--- a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
+++ b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
@@ -122,6 +122,22 @@
}
}
+ @SmallTest
+ fun testIsNonLinearFontScalingActive() {
+ assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(1f)).isFalse()
+ assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(0f)).isFalse()
+ assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(-1f)).isFalse()
+ assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(0.85f)).isFalse()
+ assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(1.02f)).isFalse()
+ assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(1.10f)).isFalse()
+ assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(1.15f)).isTrue()
+ assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(1.1499999f))
+ .isTrue()
+ assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(1.5f)).isTrue()
+ assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(2f)).isTrue()
+ assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(3f)).isTrue()
+ }
+
@LargeTest
@Test
fun allFeasibleScalesAndConversionsDoNotCrash() {
diff --git a/core/tests/utiltests/src/com/android/internal/util/QuickSelectTest.java b/core/tests/utiltests/src/com/android/internal/util/QuickSelectTest.java
new file mode 100644
index 0000000..1b9d2ef
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/QuickSelectTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2023 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.internal.util;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for {@link QuickSelect}.
+ */
+public final class QuickSelectTest extends TestCase {
+
+ public void testQuickSelect() throws Exception {
+ test((List<Integer>) null, 0, null);
+ test(Arrays.asList(), -1, null);
+ test(Arrays.asList(), 0, null);
+ test(Arrays.asList(), 1, null);
+ test(Arrays.asList(1), -1, 1, 0, null);
+ test(Arrays.asList(1), 1, -1, 0, null);
+ test(Arrays.asList(1), 0, 1, -1, null);
+ test(Arrays.asList(1), 1, 1, 0, null);
+ test(Arrays.asList(1), 0, 1);
+ test(Arrays.asList(1), 1, null);
+ test(Arrays.asList(1, 2, 3, 4, 5), 0, 1);
+ test(Arrays.asList(1, 2, 3, 4, 5), 1, 2);
+ test(Arrays.asList(1, 2, 3, 4, 5), 2, 3);
+ test(Arrays.asList(1, 2, 3, 4, 5), 3, 4);
+ test(Arrays.asList(1, 2, 3, 4, 5), 4, 5);
+ test(Arrays.asList(1, 2, 3, 4, 5), 5, null);
+ test(Arrays.asList(7, 10, 4, 3, 20, 15, 8, 9), 2, 7);
+ test(Arrays.asList(7, 10, 4, 3, 20, 15, 8, 9), 4, 9);
+ test(Arrays.asList(7, 10, 4, 3, 20, 15, 8, 9), 7, 20);
+ test(Arrays.asList(7, 10, 4, 3, 20, 15, 8, 9), 8, null);
+ test(Arrays.asList(7, 10, 4, 3, 20, 15, 8, 9), 1, 3, 0, 3);
+ test(Arrays.asList(7, 10, 4, 3, 20, 15, 8, 9), 1, 3, 1, 4);
+ test(Arrays.asList(7, 10, 4, 3, 20, 15, 8, 9), 1, 3, 2, 10);
+ test(Arrays.asList(7, 10, 4, 3, 20, 15, 8, 9), 1, 3, 3, null);
+
+ test((int[]) null, 0, null);
+ test(new int[0], -1, null);
+ test(new int[0], 0, null);
+ test(new int[0], 1, null);
+ test(new int[] {1}, -1, 1, 0, null);
+ test(new int[] {1}, 1, -1, 0, null);
+ test(new int[] {1}, 1, 0, -1, null);
+ test(new int[] {1}, 1, 1, 0, null);
+ test(new int[] {1}, 0, 1);
+ test(new int[] {1}, 1, null);
+ test(new int[] {1, 2, 3, 4, 5}, 0, 1);
+ test(new int[] {1, 2, 3, 4, 5}, 1, 2);
+ test(new int[] {1, 2, 3, 4, 5}, 2, 3);
+ test(new int[] {1, 2, 3, 4, 5}, 3, 4);
+ test(new int[] {1, 2, 3, 4, 5}, 4, 5);
+ test(new int[] {1, 2, 3, 4, 5}, 5, null);
+ test(new int[] {7, 10, 4, 3, 20, 15, 8, 9}, 2, 7);
+ test(new int[] {7, 10, 4, 3, 20, 15, 8, 9}, 4, 9);
+ test(new int[] {7, 10, 4, 3, 20, 15, 8, 9}, 7, 20);
+ test(new int[] {7, 10, 4, 3, 20, 15, 8, 9}, 8, null);
+ test(new int[] {7, 10, 4, 3, 20, 15, 8, 9}, 1, 3, 0, 3);
+ test(new int[] {7, 10, 4, 3, 20, 15, 8, 9}, 1, 3, 1, 4);
+ test(new int[] {7, 10, 4, 3, 20, 15, 8, 9}, 1, 3, 2, 10);
+ test(new int[] {7, 10, 4, 3, 20, 15, 8, 9}, 1, 3, 3, null);
+
+ test((long[]) null, 0, null);
+ test(new long[0], -1, null);
+ test(new long[0], 0, null);
+ test(new long[0], 1, null);
+ test(new long[] {1}, -1, 1, 0, null);
+ test(new long[] {1}, 1, -1, 0, null);
+ test(new long[] {1}, 1, 0, -1, null);
+ test(new long[] {1}, 1, 1, 0, null);
+ test(new long[] {1}, 0, 1L);
+ test(new long[] {1}, 1, null);
+ test(new long[] {1, 2, 3, 4, 5}, 0, 1L);
+ test(new long[] {1, 2, 3, 4, 5}, 1, 2L);
+ test(new long[] {1, 2, 3, 4, 5}, 2, 3L);
+ test(new long[] {1, 2, 3, 4, 5}, 3, 4L);
+ test(new long[] {1, 2, 3, 4, 5}, 4, 5L);
+ test(new long[] {1, 2, 3, 4, 5}, 5, null);
+ test(new long[] {7, 10, 4, 3, 20, 15, 8, 9}, 2, 7L);
+ test(new long[] {7, 10, 4, 3, 20, 15, 8, 9}, 4, 9L);
+ test(new long[] {7, 10, 4, 3, 20, 15, 8, 9}, 7, 20L);
+ test(new long[] {7, 10, 4, 3, 20, 15, 8, 9}, 8, null);
+ test(new long[] {7, 10, 4, 3, 20, 15, 8, 9}, 1, 3, 0, 3L);
+ test(new long[] {7, 10, 4, 3, 20, 15, 8, 9}, 1, 3, 1, 4L);
+ test(new long[] {7, 10, 4, 3, 20, 15, 8, 9}, 1, 3, 2, 10L);
+ test(new long[] {7, 10, 4, 3, 20, 15, 8, 9}, 1, 3, 3, null);
+ }
+
+ private void test(List<Integer> input, int k, Integer expected) throws Exception {
+ test(input, 0, input == null ? 0 : input.size(), k, expected);
+ }
+
+ private void test(List<Integer> input, int start, int length, int k, Integer expected)
+ throws Exception {
+ try {
+ final Integer result = QuickSelect.select(input, start, length, k, Integer::compare);
+ assertEquals(expected, result);
+ } catch (IllegalArgumentException e) {
+ if (expected != null) {
+ throw new Exception(e);
+ }
+ }
+ }
+
+ private void test(int[] input, int k, Integer expected) throws Exception {
+ test(input, 0, input == null ? 0 : input.length, k, expected);
+ }
+
+ private void test(int[] input, int start, int length, int k, Integer expected)
+ throws Exception {
+ try {
+ final int result = QuickSelect.select(input, start, length, k);
+ assertEquals((int) expected, result);
+ } catch (IllegalArgumentException e) {
+ if (expected != null) {
+ throw new Exception(e);
+ }
+ }
+ }
+
+ private void test(long[] input, int k, Long expected) throws Exception {
+ test(input, 0, input == null ? 0 : input.length, k, expected);
+ }
+
+ private void test(long[] input, int start, int length, int k, Long expected) throws Exception {
+ try {
+ final long result = QuickSelect.select(input, start, length, k);
+ assertEquals((long) expected, result);
+ } catch (IllegalArgumentException e) {
+ if (expected != null) {
+ throw new Exception(e);
+ }
+ }
+ }
+}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index ebfa47f..8ece337 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -122,6 +122,7 @@
<permission name="android.permission.BIND_CARRIER_SERVICES"/>
<permission name="android.permission.BIND_CELL_BROADCAST_SERVICE"/>
<permission name="android.permission.BIND_IMS_SERVICE"/>
+ <permission name="android.permission.BIND_SATELLITE_GATEWAY_SERVICE"/>
<permission name="android.permission.BIND_SATELLITE_SERVICE"/>
<permission name="android.permission.BIND_TELEPHONY_DATA_SERVICE"/>
<permission name="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"/>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 79e0a48..d3f3958 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -64,7 +64,11 @@
public class Bubble implements BubbleViewProvider {
private static final String TAG = "Bubble";
- public static final String KEY_APP_BUBBLE = "key_app_bubble";
+ /** A string suffix used in app bubbles' {@link #mKey}. */
+ private static final String KEY_APP_BUBBLE = "key_app_bubble";
+
+ /** Whether the bubble is an app bubble. */
+ private final boolean mIsAppBubble;
private final String mKey;
@Nullable
@@ -181,7 +185,7 @@
private PendingIntent mDeleteIntent;
/**
- * Used only for a special bubble in the stack that has the key {@link #KEY_APP_BUBBLE}.
+ * Used only for a special bubble in the stack that has {@link #mIsAppBubble} set to true.
* There can only be one of these bubbles in the stack and this intent will be populated for
* that bubble.
*/
@@ -216,24 +220,54 @@
mMainExecutor = mainExecutor;
mTaskId = taskId;
mBubbleMetadataFlagListener = listener;
+ mIsAppBubble = false;
}
- public Bubble(Intent intent,
+ private Bubble(
+ Intent intent,
UserHandle user,
@Nullable Icon icon,
+ boolean isAppBubble,
+ String key,
Executor mainExecutor) {
- mKey = KEY_APP_BUBBLE;
mGroupKey = null;
mLocusId = null;
mFlags = 0;
mUser = user;
mIcon = icon;
+ mIsAppBubble = isAppBubble;
+ mKey = key;
mShowBubbleUpdateDot = false;
mMainExecutor = mainExecutor;
mTaskId = INVALID_TASK_ID;
mAppIntent = intent;
mDesiredHeight = Integer.MAX_VALUE;
mPackageName = intent.getPackage();
+
+ }
+
+ /** Creates an app bubble. */
+ public static Bubble createAppBubble(
+ Intent intent,
+ UserHandle user,
+ @Nullable Icon icon,
+ Executor mainExecutor) {
+ return new Bubble(intent,
+ user,
+ icon,
+ /* isAppBubble= */ true,
+ /* key= */ getAppBubbleKeyForApp(intent.getPackage(), user),
+ mainExecutor);
+ }
+
+ /**
+ * Returns the key for an app bubble from an app with package name, {@code packageName} on an
+ * Android user, {@code user}.
+ */
+ public static String getAppBubbleKeyForApp(String packageName, UserHandle user) {
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(user);
+ return KEY_APP_BUBBLE + ":" + user.getIdentifier() + ":" + packageName;
}
@VisibleForTesting(visibility = PRIVATE)
@@ -241,6 +275,7 @@
final Bubbles.BubbleMetadataFlagListener listener,
final Bubbles.PendingIntentCanceledListener intentCancelListener,
Executor mainExecutor) {
+ mIsAppBubble = false;
mKey = entry.getKey();
mGroupKey = entry.getGroupKey();
mLocusId = entry.getLocusId();
@@ -815,7 +850,7 @@
}
boolean isAppBubble() {
- return KEY_APP_BUBBLE.equals(mKey);
+ return mIsAppBubble;
}
Intent getSettingsIntent(final Context context) {
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 c407b06..21f02b1 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
@@ -24,7 +24,6 @@
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static com.android.wm.shell.bubbles.Bubble.KEY_APP_BUBBLE;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_GESTURE;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
@@ -1193,14 +1192,15 @@
return;
}
+ String appBubbleKey = Bubble.getAppBubbleKeyForApp(intent.getPackage(), user);
PackageManager packageManager = getPackageManagerForUser(mContext, user.getIdentifier());
- if (!isResizableActivity(intent, packageManager, KEY_APP_BUBBLE)) return;
+ if (!isResizableActivity(intent, packageManager, appBubbleKey)) return;
- Bubble existingAppBubble = mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE);
+ Bubble existingAppBubble = mBubbleData.getBubbleInStackWithKey(appBubbleKey);
if (existingAppBubble != null) {
BubbleViewProvider selectedBubble = mBubbleData.getSelectedBubble();
if (isStackExpanded()) {
- if (selectedBubble != null && KEY_APP_BUBBLE.equals(selectedBubble.getKey())) {
+ if (selectedBubble != null && appBubbleKey.equals(selectedBubble.getKey())) {
// App bubble is expanded, lets collapse
collapseStack();
} else {
@@ -1214,7 +1214,7 @@
}
} else {
// App bubble does not exist, lets add and expand it
- Bubble b = new Bubble(intent, user, icon, mMainExecutor);
+ Bubble b = Bubble.createAppBubble(intent, user, icon, mMainExecutor);
b.setShouldAutoExpand(true);
inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false);
}
@@ -1247,8 +1247,8 @@
}
/** Sets the app bubble's taskId which is cached for SysUI. */
- public void setAppBubbleTaskId(int taskId) {
- mImpl.mCachedState.setAppBubbleTaskId(taskId);
+ public void setAppBubbleTaskId(String key, int taskId) {
+ mImpl.mCachedState.setAppBubbleTaskId(key, taskId);
}
/**
@@ -2045,7 +2045,8 @@
private HashSet<String> mSuppressedBubbleKeys = new HashSet<>();
private HashMap<String, String> mSuppressedGroupToNotifKeys = new HashMap<>();
private HashMap<String, Bubble> mShortcutIdToBubble = new HashMap<>();
- private int mAppBubbleTaskId = INVALID_TASK_ID;
+
+ private HashMap<String, Integer> mAppBubbleTaskIds = new HashMap();
private ArrayList<Bubble> mTmpBubbles = new ArrayList<>();
@@ -2077,20 +2078,20 @@
mSuppressedBubbleKeys.clear();
mShortcutIdToBubble.clear();
- mAppBubbleTaskId = INVALID_TASK_ID;
+ mAppBubbleTaskIds.clear();
for (Bubble b : mTmpBubbles) {
mShortcutIdToBubble.put(b.getShortcutId(), b);
updateBubbleSuppressedState(b);
- if (KEY_APP_BUBBLE.equals(b.getKey())) {
- mAppBubbleTaskId = b.getTaskId();
+ if (b.isAppBubble()) {
+ mAppBubbleTaskIds.put(b.getKey(), b.getTaskId());
}
}
}
/** Sets the app bubble's taskId which is cached for SysUI. */
- synchronized void setAppBubbleTaskId(int taskId) {
- mAppBubbleTaskId = taskId;
+ synchronized void setAppBubbleTaskId(String key, int taskId) {
+ mAppBubbleTaskIds.put(key, taskId);
}
/**
@@ -2143,7 +2144,7 @@
pw.println(" suppressing: " + key);
}
- pw.print("mAppBubbleTaskId: " + mAppBubbleTaskId);
+ pw.print("mAppBubbleTaskIds: " + mAppBubbleTaskIds.values());
}
}
@@ -2205,7 +2206,7 @@
@Override
public boolean isAppBubbleTaskId(int taskId) {
- return mCachedState.mAppBubbleTaskId == taskId;
+ return mCachedState.mAppBubbleTaskIds.values().contains(taskId);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 92b969b..cc8f50e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -17,7 +17,6 @@
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
-import static com.android.wm.shell.bubbles.Bubble.KEY_APP_BUBBLE;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_DATA;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -780,7 +779,7 @@
|| !(reason == Bubbles.DISMISS_AGED
|| reason == Bubbles.DISMISS_USER_GESTURE
|| reason == Bubbles.DISMISS_RELOAD_FROM_DISK)
- || KEY_APP_BUBBLE.equals(bubble.getKey())) {
+ || bubble.isAppBubble()) {
return;
}
if (DEBUG_BUBBLE_DATA) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 684a23a..6c482c8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -287,9 +287,9 @@
// The taskId is saved to use for removeTask, preventing appearance in recent tasks.
mTaskId = taskId;
- if (Bubble.KEY_APP_BUBBLE.equals(getBubbleKey())) {
+ if (mBubble != null && mBubble.isAppBubble()) {
// Let the controller know sooner what the taskId is.
- mController.setAppBubbleTaskId(mTaskId);
+ mController.setAppBubbleTaskId(mBubble.getKey(), mTaskId);
}
// With the task org, the taskAppeared callback will only happen once the task has
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index 4970fa0..56616cb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -165,6 +165,10 @@
t.remove(mGapBackgroundLeash);
mGapBackgroundLeash = null;
}
+ if (mScreenshot != null) {
+ t.remove(mScreenshot);
+ mScreenshot = null;
+ }
mHostLeash = null;
mIcon = null;
mResizingIconView = null;
@@ -324,6 +328,8 @@
if (!mShown && mIsResizing && !mOldBounds.equals(mResizingBounds)) {
if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) {
mScreenshotAnimator.cancel();
+ } else if (mScreenshot != null) {
+ t.remove(mScreenshot);
}
mTempRect.set(mOldBounds);
@@ -340,6 +346,8 @@
if (!mShown && mIsResizing && !mOldBounds.equals(mResizingBounds)) {
if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) {
mScreenshotAnimator.cancel();
+ } else if (mScreenshot != null) {
+ t.remove(mScreenshot);
}
mScreenshot = screenshot;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 24dee5f..c8062bc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -146,13 +146,17 @@
t.apply();
// execute the runnable if non-null after WCT is applied to finish resizing pip
- if (mPipFinishResizeWCTRunnable != null) {
- mPipFinishResizeWCTRunnable.run();
- mPipFinishResizeWCTRunnable = null;
- }
+ maybePerformFinishResizeCallback();
}
};
+ private void maybePerformFinishResizeCallback() {
+ if (mPipFinishResizeWCTRunnable != null) {
+ mPipFinishResizeWCTRunnable.run();
+ mPipFinishResizeWCTRunnable = null;
+ }
+ }
+
// These callbacks are called on the update thread
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
new PipAnimationController.PipAnimationCallback() {
@@ -619,11 +623,11 @@
* Removes PiP immediately.
*/
public void removePip() {
- if (!mPipTransitionState.isInPip() || mToken == null) {
+ if (!mPipTransitionState.isInPip() || mToken == null || mLeash == null) {
ProtoLog.wtf(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: Not allowed to removePip in current state"
- + " mState=%d mToken=%s", TAG, mPipTransitionState.getTransitionState(),
- mToken);
+ + " mState=%d mToken=%s mLeash=%s", TAG,
+ mPipTransitionState.getTransitionState(), mToken, mLeash);
return;
}
@@ -1607,6 +1611,10 @@
if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
mSplitScreenOptional.ifPresent(splitScreenController ->
splitScreenController.enterSplitScreen(mTaskInfo.taskId, wasPipTopLeft, wct));
+ } else if (direction == TRANSITION_DIRECTION_LEAVE_PIP) {
+ // when leaving PiP we can call the callback without sync
+ maybePerformFinishResizeCallback();
+ mTaskOrganizer.applyTransaction(wct);
} else {
mTaskOrganizer.applySyncTransaction(wct, mPipFinishResizeWCTCallback);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 44d7e6d..a8b209f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -213,12 +213,7 @@
RecentsController(IRecentsAnimationRunner listener) {
mListener = listener;
- mDeathHandler = () -> mExecutor.execute(() -> {
- if (mListener == null) return;
- if (mFinishCB != null) {
- finish(mWillFinishToHome, false /* leaveHint */);
- }
- });
+ mDeathHandler = () -> finish(mWillFinishToHome, false /* leaveHint */);
try {
mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */);
} catch (RemoteException e) {
@@ -245,7 +240,7 @@
}
}
if (mFinishCB != null) {
- finish(toHome, false /* userLeave */);
+ finishInner(toHome, false /* userLeave */);
} else {
cleanUp();
}
@@ -552,13 +547,13 @@
t.apply();
// not using the incoming anim-only surfaces
info.releaseAnimSurfaces();
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
if (appearedTargets == null) return;
try {
mListener.onTasksAppeared(appearedTargets);
} catch (RemoteException e) {
Slog.e(TAG, "Error sending appeared tasks to recents animation", e);
}
+ finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
}
/** For now, just set-up a jump-cut to the new activity. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 8e8faca..e8a6a15 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -127,7 +127,7 @@
if (decoration == null) {
createWindowDecoration(taskInfo, taskSurface, startT, finishT);
} else {
- decoration.relayout(taskInfo, startT, finishT);
+ decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */);
}
}
@@ -139,7 +139,7 @@
final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
if (decoration == null) return;
- decoration.relayout(taskInfo, startT, finishT);
+ decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */);
}
@Override
@@ -192,7 +192,8 @@
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
windowDecoration.setDragPositioningCallback(taskPositioner);
windowDecoration.setDragDetector(touchEventListener.mDragDetector);
- windowDecoration.relayout(taskInfo, startT, finishT);
+ windowDecoration.relayout(taskInfo, startT, finishT,
+ false /* applyStartTransactionOnDraw */);
setupCaptionColor(taskInfo, windowDecoration);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index dfde7e6..116af70 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -90,15 +90,15 @@
@Override
void relayout(RunningTaskInfo taskInfo) {
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- relayout(taskInfo, t, t);
- mSyncQueue.runInSync(transaction -> {
- transaction.merge(t);
- t.close();
- });
+ // Use |applyStartTransactionOnDraw| so that the transaction (that applies task crop) is
+ // synced with the buffer transaction (that draws the View). Both will be shown on screen
+ // at the same, whereas applying them independently causes flickering. See b/270202228.
+ relayout(taskInfo, t, t, true /* applyStartTransactionOnDraw */);
}
void relayout(RunningTaskInfo taskInfo,
- SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) {
+ SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
+ boolean applyStartTransactionOnDraw) {
final int shadowRadiusID = taskInfo.isFocused
? R.dimen.freeform_decor_shadow_focused_thickness
: R.dimen.freeform_decor_shadow_unfocused_thickness;
@@ -115,6 +115,7 @@
mRelayoutParams.mLayoutResId = R.layout.caption_window_decor;
mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height;
mRelayoutParams.mShadowRadiusId = shadowRadiusID;
+ mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
// After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index e137bc4..49a5eac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -247,7 +247,7 @@
if (decoration == null) {
createWindowDecoration(taskInfo, taskSurface, startT, finishT);
} else {
- decoration.relayout(taskInfo, startT, finishT);
+ decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */);
}
}
@@ -259,7 +259,7 @@
final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
if (decoration == null) return;
- decoration.relayout(taskInfo, startT, finishT);
+ decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */);
}
@Override
@@ -781,7 +781,8 @@
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
windowDecoration.setDragPositioningCallback(taskPositioner);
windowDecoration.setDragDetector(touchEventListener.mDragDetector);
- windowDecoration.relayout(taskInfo, startT, finishT);
+ windowDecoration.relayout(taskInfo, startT, finishT,
+ false /* applyStartTransactionOnDraw */);
incrementEventReceiverTasks(taskInfo.displayId);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 67e99d7..af3fb0e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -173,15 +173,15 @@
@Override
void relayout(ActivityManager.RunningTaskInfo taskInfo) {
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- relayout(taskInfo, t, t);
- mSyncQueue.runInSync(transaction -> {
- transaction.merge(t);
- t.close();
- });
+ // Use |applyStartTransactionOnDraw| so that the transaction (that applies task crop) is
+ // synced with the buffer transaction (that draws the View). Both will be shown on screen
+ // at the same, whereas applying them independently causes flickering. See b/270202228.
+ relayout(taskInfo, t, t, true /* applyStartTransactionOnDraw */);
}
void relayout(ActivityManager.RunningTaskInfo taskInfo,
- SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) {
+ SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
+ boolean applyStartTransactionOnDraw) {
final int shadowRadiusID = taskInfo.isFocused
? R.dimen.freeform_decor_shadow_focused_thickness
: R.dimen.freeform_decor_shadow_unfocused_thickness;
@@ -216,6 +216,7 @@
mRelayoutParams.mLayoutResId = windowDecorLayoutId;
mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height;
mRelayoutParams.mShadowRadiusId = shadowRadiusID;
+ mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
// After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 8b35694..9a1b4ff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -238,30 +238,6 @@
startT.setWindowCrop(mCaptionContainerSurface, captionWidth, captionHeight)
.show(mCaptionContainerSurface);
- if (mCaptionWindowManager == null) {
- // Put caption under a container surface because ViewRootImpl sets the destination frame
- // of windowless window layers and BLASTBufferQueue#update() doesn't support offset.
- mCaptionWindowManager = new WindowlessWindowManager(
- mTaskInfo.getConfiguration(), mCaptionContainerSurface,
- null /* hostInputToken */);
- }
-
- // Caption view
- mCaptionWindowManager.setConfiguration(taskConfig);
- final WindowManager.LayoutParams lp =
- new WindowManager.LayoutParams(captionWidth, captionHeight,
- WindowManager.LayoutParams.TYPE_APPLICATION,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
- lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
- lp.setTrustedOverlay();
- if (mViewHost == null) {
- mViewHost = mSurfaceControlViewHostFactory.create(mDecorWindowContext, mDisplay,
- mCaptionWindowManager);
- mViewHost.setView(outResult.mRootView, lp);
- } else {
- mViewHost.relayout(lp);
- }
-
if (ViewRootImpl.CAPTION_ON_SHELL) {
outResult.mRootView.setTaskFocusState(mTaskInfo.isFocused);
@@ -287,6 +263,36 @@
.show(mTaskSurface);
finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y)
.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight);
+
+ if (mCaptionWindowManager == null) {
+ // Put caption under a container surface because ViewRootImpl sets the destination frame
+ // of windowless window layers and BLASTBufferQueue#update() doesn't support offset.
+ mCaptionWindowManager = new WindowlessWindowManager(
+ mTaskInfo.getConfiguration(), mCaptionContainerSurface,
+ null /* hostInputToken */);
+ }
+
+ // Caption view
+ mCaptionWindowManager.setConfiguration(taskConfig);
+ final WindowManager.LayoutParams lp =
+ new WindowManager.LayoutParams(captionWidth, captionHeight,
+ WindowManager.LayoutParams.TYPE_APPLICATION,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
+ lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
+ lp.setTrustedOverlay();
+ if (mViewHost == null) {
+ mViewHost = mSurfaceControlViewHostFactory.create(mDecorWindowContext, mDisplay,
+ mCaptionWindowManager);
+ if (params.mApplyStartTransactionOnDraw) {
+ mViewHost.getRootSurfaceControl().applyTransactionOnDraw(startT);
+ }
+ mViewHost.setView(outResult.mRootView, lp);
+ } else {
+ if (params.mApplyStartTransactionOnDraw) {
+ mViewHost.getRootSurfaceControl().applyTransactionOnDraw(startT);
+ }
+ mViewHost.relayout(lp);
+ }
}
/**
@@ -411,6 +417,8 @@
int mCaptionX;
int mCaptionY;
+ boolean mApplyStartTransactionOnDraw;
+
void reset() {
mLayoutResId = Resources.ID_NULL;
mCaptionHeightId = Resources.ID_NULL;
@@ -419,6 +427,8 @@
mCaptionX = 0;
mCaptionY = 0;
+
+ mApplyStartTransactionOnDraw = false;
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index 919bf06..4a55429 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -16,8 +16,6 @@
package com.android.wm.shell.bubbles;
-import static com.android.wm.shell.bubbles.Bubble.KEY_APP_BUBBLE;
-
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -185,7 +183,10 @@
Intent appBubbleIntent = new Intent(mContext, BubblesTestActivity.class);
appBubbleIntent.setPackage(mContext.getPackageName());
- mAppBubble = new Bubble(appBubbleIntent, new UserHandle(1), mock(Icon.class),
+ mAppBubble = Bubble.createAppBubble(
+ appBubbleIntent,
+ new UserHandle(1),
+ mock(Icon.class),
mMainExecutor);
mPositioner = new TestableBubblePositioner(mContext,
@@ -1101,14 +1102,15 @@
@Test
public void test_removeAppBubble_skipsOverflow() {
+ String appBubbleKey = mAppBubble.getKey();
mBubbleData.notificationEntryUpdated(mAppBubble, true /* suppressFlyout*/,
false /* showInShade */);
- assertThat(mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE)).isEqualTo(mAppBubble);
+ assertThat(mBubbleData.getBubbleInStackWithKey(appBubbleKey)).isEqualTo(mAppBubble);
- mBubbleData.dismissBubbleWithKey(KEY_APP_BUBBLE, Bubbles.DISMISS_USER_GESTURE);
+ mBubbleData.dismissBubbleWithKey(appBubbleKey, Bubbles.DISMISS_USER_GESTURE);
- assertThat(mBubbleData.getOverflowBubbleWithKey(KEY_APP_BUBBLE)).isNull();
- assertThat(mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE)).isNull();
+ assertThat(mBubbleData.getOverflowBubbleWithKey(appBubbleKey)).isNull();
+ assertThat(mBubbleData.getBubbleInStackWithKey(appBubbleKey)).isNull();
}
private void verifyUpdateReceived() {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index c1e53a9..fc4bfd97 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -33,6 +33,7 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.same;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.content.Context;
@@ -42,6 +43,7 @@
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.util.DisplayMetrics;
+import android.view.AttachedSurfaceControl;
import android.view.Display;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
@@ -97,6 +99,8 @@
@Mock
private SurfaceControlViewHost mMockSurfaceControlViewHost;
@Mock
+ private AttachedSurfaceControl mMockRootSurfaceControl;
+ @Mock
private TestView mMockView;
@Mock
private WindowContainerTransaction mMockWindowContainerTransaction;
@@ -129,6 +133,8 @@
doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory)
.create(any(), any(), any());
+ when(mMockSurfaceControlViewHost.getRootSurfaceControl())
+ .thenReturn(mMockRootSurfaceControl);
}
@Test
@@ -461,6 +467,43 @@
verify(mMockSurfaceControlStartT).show(captionContainerSurface);
}
+ @Test
+ public void testRelayout_applyTransactionInSyncWithDraw() {
+ final Display defaultDisplay = mock(Display.class);
+ doReturn(defaultDisplay).when(mMockDisplayController)
+ .getDisplay(Display.DEFAULT_DISPLAY);
+
+ final SurfaceControl decorContainerSurface = mock(SurfaceControl.class);
+ final SurfaceControl.Builder decorContainerSurfaceBuilder =
+ createMockSurfaceControlBuilder(decorContainerSurface);
+ mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
+ final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
+ final SurfaceControl.Builder captionContainerSurfaceBuilder =
+ createMockSurfaceControlBuilder(captionContainerSurface);
+ mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
+
+ final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+ mMockSurfaceControlTransactions.add(t);
+ final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
+ new ActivityManager.TaskDescription.Builder()
+ .setBackgroundColor(Color.YELLOW);
+ final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
+ .setDisplayId(Display.DEFAULT_DISPLAY)
+ .setTaskDescriptionBuilder(taskDescriptionBuilder)
+ .setBounds(TASK_BOUNDS)
+ .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y)
+ .setVisible(true)
+ .build();
+ taskInfo.isFocused = true;
+ taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
+ final SurfaceControl taskSurface = mock(SurfaceControl.class);
+ final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
+
+ windowDecor.relayout(taskInfo, true /* applyStartTransactionOnDraw */);
+
+ verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockSurfaceControlStartT);
+ }
+
private TestWindowDecoration createWindowDecoration(
ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) {
return new TestWindowDecoration(InstrumentationRegistry.getInstrumentation().getContext(),
@@ -516,6 +559,12 @@
@Override
void relayout(ActivityManager.RunningTaskInfo taskInfo) {
+ relayout(taskInfo, false /* applyStartTransactionOnDraw */);
+ }
+
+ void relayout(ActivityManager.RunningTaskInfo taskInfo,
+ boolean applyStartTransactionOnDraw) {
+ mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT,
mMockWindowContainerTransaction, mMockView, mRelayoutResult);
}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 70c36a5..34af1f9 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -399,7 +399,7 @@
"libharfbuzz_ng",
"libimage_io",
"libjpeg",
- "libjpegrecoverymap",
+ "libultrahdr",
"liblog",
"libminikin",
"libz",
diff --git a/libs/hwui/jni/YuvToJpegEncoder.cpp b/libs/hwui/jni/YuvToJpegEncoder.cpp
index 8874ef1..69418b0 100644
--- a/libs/hwui/jni/YuvToJpegEncoder.cpp
+++ b/libs/hwui/jni/YuvToJpegEncoder.cpp
@@ -298,39 +298,39 @@
}
///////////////////////////////////////////////////////////////////////////////
-using namespace android::jpegrecoverymap;
+using namespace android::ultrahdr;
-jpegr_color_gamut P010Yuv420ToJpegREncoder::findColorGamut(JNIEnv* env, int aDataSpace) {
+ultrahdr_color_gamut P010Yuv420ToJpegREncoder::findColorGamut(JNIEnv* env, int aDataSpace) {
switch (aDataSpace & ADataSpace::STANDARD_MASK) {
case ADataSpace::STANDARD_BT709:
- return jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
+ return ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
case ADataSpace::STANDARD_DCI_P3:
- return jpegr_color_gamut::JPEGR_COLORGAMUT_P3;
+ return ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_P3;
case ADataSpace::STANDARD_BT2020:
- return jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
+ return ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100;
default:
jclass IllegalArgumentException = env->FindClass("java/lang/IllegalArgumentException");
env->ThrowNew(IllegalArgumentException,
"The requested color gamut is not supported by JPEG/R.");
}
- return jpegr_color_gamut::JPEGR_COLORGAMUT_UNSPECIFIED;
+ return ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED;
}
-jpegr_transfer_function P010Yuv420ToJpegREncoder::findHdrTransferFunction(JNIEnv* env,
+ultrahdr_transfer_function P010Yuv420ToJpegREncoder::findHdrTransferFunction(JNIEnv* env,
int aDataSpace) {
switch (aDataSpace & ADataSpace::TRANSFER_MASK) {
case ADataSpace::TRANSFER_ST2084:
- return jpegr_transfer_function::JPEGR_TF_PQ;
+ return ultrahdr_transfer_function::ULTRAHDR_TF_PQ;
case ADataSpace::TRANSFER_HLG:
- return jpegr_transfer_function::JPEGR_TF_HLG;
+ return ultrahdr_transfer_function::ULTRAHDR_TF_HLG;
default:
jclass IllegalArgumentException = env->FindClass("java/lang/IllegalArgumentException");
env->ThrowNew(IllegalArgumentException,
"The requested HDR transfer function is not supported by JPEG/R.");
}
- return jpegr_transfer_function::JPEGR_TF_UNSPECIFIED;
+ return ultrahdr_transfer_function::ULTRAHDR_TF_UNSPECIFIED;
}
bool P010Yuv420ToJpegREncoder::encode(JNIEnv* env,
@@ -344,13 +344,13 @@
return false;
}
- jpegr_color_gamut hdrColorGamut = findColorGamut(env, hdrColorSpace);
- jpegr_color_gamut sdrColorGamut = findColorGamut(env, sdrColorSpace);
- jpegr_transfer_function hdrTransferFunction = findHdrTransferFunction(env, hdrColorSpace);
+ ultrahdr_color_gamut hdrColorGamut = findColorGamut(env, hdrColorSpace);
+ ultrahdr_color_gamut sdrColorGamut = findColorGamut(env, sdrColorSpace);
+ ultrahdr_transfer_function hdrTransferFunction = findHdrTransferFunction(env, hdrColorSpace);
- if (hdrColorGamut == jpegr_color_gamut::JPEGR_COLORGAMUT_UNSPECIFIED
- || sdrColorGamut == jpegr_color_gamut::JPEGR_COLORGAMUT_UNSPECIFIED
- || hdrTransferFunction == jpegr_transfer_function::JPEGR_TF_UNSPECIFIED) {
+ if (hdrColorGamut == ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED
+ || sdrColorGamut == ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED
+ || hdrTransferFunction == ultrahdr_transfer_function::ULTRAHDR_TF_UNSPECIFIED) {
return false;
}
diff --git a/libs/hwui/jni/YuvToJpegEncoder.h b/libs/hwui/jni/YuvToJpegEncoder.h
index d22a26c..8ef7805 100644
--- a/libs/hwui/jni/YuvToJpegEncoder.h
+++ b/libs/hwui/jni/YuvToJpegEncoder.h
@@ -2,7 +2,7 @@
#define _ANDROID_GRAPHICS_YUV_TO_JPEG_ENCODER_H_
#include <android/data_space.h>
-#include <jpegrecoverymap/jpegr.h>
+#include <ultrahdr/jpegr.h>
extern "C" {
#include "jpeglib.h"
@@ -103,7 +103,7 @@
* @param aDataSpace data space defined in data_space.h.
* @return color gamut for JPEG/R.
*/
- static android::jpegrecoverymap::jpegr_color_gamut findColorGamut(JNIEnv* env, int aDataSpace);
+ static android::ultrahdr::ultrahdr_color_gamut findColorGamut(JNIEnv* env, int aDataSpace);
/** Map data space (defined in DataSpace.java and data_space.h) to the transfer function
* used in JPEG/R
@@ -112,7 +112,7 @@
* @param aDataSpace data space defined in data_space.h.
* @return color gamut for JPEG/R.
*/
- static android::jpegrecoverymap::jpegr_transfer_function findHdrTransferFunction(
+ static android::ultrahdr::ultrahdr_transfer_function findHdrTransferFunction(
JNIEnv* env, int aDataSpace);
};
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 7e1bbe3..29e8716 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -293,12 +293,16 @@
* Set the component name of the manifest-declared {@link android.content.BroadcastReceiver}
* class that should receive media buttons. This allows restarting playback after the session
* has been stopped. If your app is started in this way an {@link Intent#ACTION_MEDIA_BUTTON}
- * intent will be sent to the broadcast receiver.
- * <p>
- * Note: The given {@link android.content.BroadcastReceiver} should belong to the same package
- * as the context that was given when creating {@link MediaSession}.
+ * intent will be sent to the broadcast receiver. On apps targeting Android U and above, this
+ * will throw an {@link IllegalArgumentException} if the provided {@link ComponentName} does not
+ * resolve to an existing {@link android.content.BroadcastReceiver broadcast receiver}.
+ *
+ * <p>Note: The given {@link android.content.BroadcastReceiver} should belong to the same
+ * package as the context that was given when creating {@link MediaSession}.
*
* @param broadcastReceiver the component name of the BroadcastReceiver class
+ * @throws IllegalArgumentException if {@code broadcastReceiver} does not exist on apps
+ * targeting Android U and above
*/
public void setMediaButtonBroadcastReceiver(@Nullable ComponentName broadcastReceiver) {
try {
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index 7581b5c..8b9c8b9 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -40,9 +40,7 @@
import com.android.credentialmanager.createflow.CreateCredentialScreen
import com.android.credentialmanager.createflow.hasContentToDisplay
import com.android.credentialmanager.getflow.GetCredentialScreen
-import com.android.credentialmanager.getflow.GetGenericCredentialScreen
import com.android.credentialmanager.getflow.hasContentToDisplay
-import com.android.credentialmanager.getflow.isFallbackScreen
import com.android.credentialmanager.ui.theme.PlatformTheme
@ExperimentalMaterialApi
@@ -161,19 +159,11 @@
providerActivityLauncher = launcher
)
} else if (getCredentialUiState != null && hasContentToDisplay(getCredentialUiState)) {
- if (isFallbackScreen(getCredentialUiState)) {
- GetGenericCredentialScreen(
- viewModel = viewModel,
- getCredentialUiState = getCredentialUiState,
- providerActivityLauncher = launcher
- )
- } else {
- GetCredentialScreen(
- viewModel = viewModel,
- getCredentialUiState = getCredentialUiState,
- providerActivityLauncher = launcher
- )
- }
+ GetCredentialScreen(
+ viewModel = viewModel,
+ getCredentialUiState = getCredentialUiState,
+ providerActivityLauncher = launcher
+ )
} else {
Log.d(Constants.LOG_TAG, "UI wasn't able to render neither get nor create flow")
reportInstantiationErrorAndFinishActivity(credManRepo)
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index f08bbf4..57035d4 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -50,9 +50,7 @@
import androidx.credentials.CreateCredentialRequest
import androidx.credentials.CreateCustomCredentialRequest
import androidx.credentials.CreatePasswordRequest
-import androidx.credentials.CredentialOption
import androidx.credentials.CreatePublicKeyCredentialRequest
-import androidx.credentials.GetPublicKeyCredentialOption
import androidx.credentials.PublicKeyCredential.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
import androidx.credentials.provider.Action
import androidx.credentials.provider.AuthenticationAction
@@ -194,20 +192,8 @@
originName: String?,
): com.android.credentialmanager.getflow.RequestDisplayInfo? {
val getCredentialRequest = requestInfo?.getCredentialRequest ?: return null
- val preferImmediatelyAvailableCredentials = getCredentialRequest.credentialOptions.any {
- val credentialOptionJetpack = CredentialOption.createFrom(
- it.type,
- it.credentialRetrievalData,
- it.credentialRetrievalData,
- it.isSystemProviderRequired,
- it.allowedProviders,
- )
- if (credentialOptionJetpack is GetPublicKeyCredentialOption) {
- credentialOptionJetpack.preferImmediatelyAvailableCredentials
- } else {
- false
- }
- }
+ val preferImmediatelyAvailableCredentials = getCredentialRequest.data.getBoolean(
+ "androidx.credentials.BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS")
val preferUiBrandingComponentName =
getCredentialRequest.data.getParcelable(
"androidx.credentials.BUNDLE_KEY_PREFER_UI_BRANDING_COMPONENT_NAME",
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index 516c1a3..74933c9 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -200,18 +200,31 @@
authenticationEntryList.isEmpty()) || (sortedUserNameToCredentialEntryList.isEmpty() &&
authenticationEntryList.size == 1)
item {
- HeadlineText(
- text = stringResource(
- if (hasSingleEntry) {
- if (sortedUserNameToCredentialEntryList.firstOrNull()
- ?.sortedCredentialEntryList?.first()?.credentialType
- == CredentialType.PASSKEY
- ) R.string.get_dialog_title_use_passkey_for
- else R.string.get_dialog_title_use_sign_in_for
- } else R.string.get_dialog_title_choose_sign_in_for,
- requestDisplayInfo.appName
- ),
- )
+ if (requestDisplayInfo.preferIdentityDocUi) {
+ HeadlineText(
+ text = stringResource(
+ if (hasSingleEntry) {
+ R.string.get_dialog_title_use_info_on
+ } else {
+ R.string.get_dialog_title_choose_option_for
+ },
+ requestDisplayInfo.appName
+ ),
+ )
+ } else {
+ HeadlineText(
+ text = stringResource(
+ if (hasSingleEntry) {
+ if (sortedUserNameToCredentialEntryList.firstOrNull()
+ ?.sortedCredentialEntryList?.first()?.credentialType
+ == CredentialType.PASSKEY
+ ) R.string.get_dialog_title_use_passkey_for
+ else R.string.get_dialog_title_use_sign_in_for
+ } else R.string.get_dialog_title_choose_sign_in_for,
+ requestDisplayInfo.appName
+ ),
+ )
+ }
}
item { Divider(thickness = 24.dp, color = Color.Transparent) }
item {
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetGenericCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetGenericCredentialComponents.kt
deleted file mode 100644
index 57fefbe..0000000
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetGenericCredentialComponents.kt
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2023 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.credentialmanager.getflow
-
-import androidx.activity.compose.ManagedActivityResultLauncher
-import androidx.activity.result.ActivityResult
-import androidx.activity.result.IntentSenderRequest
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Column
-import androidx.compose.material3.Divider
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.asImageBitmap
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.unit.dp
-import androidx.core.graphics.drawable.toBitmap
-import com.android.compose.rememberSystemUiController
-import com.android.credentialmanager.CredentialSelectorViewModel
-import com.android.credentialmanager.R
-import com.android.credentialmanager.common.BaseEntry
-import com.android.credentialmanager.common.ProviderActivityState
-import com.android.credentialmanager.common.ui.ConfirmButton
-import com.android.credentialmanager.common.ui.CredentialContainerCard
-import com.android.credentialmanager.common.ui.CtaButtonRow
-import com.android.credentialmanager.common.ui.HeadlineIcon
-import com.android.credentialmanager.common.ui.HeadlineText
-import com.android.credentialmanager.common.ui.LargeLabelTextOnSurfaceVariant
-import com.android.credentialmanager.common.ui.ModalBottomSheet
-import com.android.credentialmanager.common.ui.SheetContainerCard
-import com.android.credentialmanager.common.ui.setBottomSheetSystemBarsColor
-import com.android.credentialmanager.logging.GetCredentialEvent
-import com.android.internal.logging.UiEventLogger
-
-
-@Composable
-fun GetGenericCredentialScreen(
- viewModel: CredentialSelectorViewModel,
- getCredentialUiState: GetCredentialUiState,
- providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
-) {
- val sysUiController = rememberSystemUiController()
- setBottomSheetSystemBarsColor(sysUiController)
- ModalBottomSheet(
- sheetContent = {
- when (viewModel.uiState.providerActivityState) {
- ProviderActivityState.NOT_APPLICABLE -> {
- PrimarySelectionCardGeneric(
- requestDisplayInfo = getCredentialUiState.requestDisplayInfo,
- providerDisplayInfo = getCredentialUiState.providerDisplayInfo,
- providerInfoList = getCredentialUiState.providerInfoList,
- onEntrySelected = viewModel::getFlowOnEntrySelected,
- onConfirm = viewModel::getFlowOnConfirmEntrySelected,
- onLog = { viewModel.logUiEvent(it) },
- )
- viewModel.uiMetrics.log(GetCredentialEvent
- .CREDMAN_GET_CRED_SCREEN_PRIMARY_SELECTION)
- }
- ProviderActivityState.READY_TO_LAUNCH -> {
- // Launch only once per providerActivityState change so that the provider
- // UI will not be accidentally launched twice.
- LaunchedEffect(viewModel.uiState.providerActivityState) {
- viewModel.launchProviderUi(providerActivityLauncher)
- }
- viewModel.uiMetrics.log(GetCredentialEvent
- .CREDMAN_GET_CRED_PROVIDER_ACTIVITY_READY_TO_LAUNCH)
- }
- ProviderActivityState.PENDING -> {
- // Hide our content when the provider activity is active.
- viewModel.uiMetrics.log(GetCredentialEvent
- .CREDMAN_GET_CRED_PROVIDER_ACTIVITY_PENDING)
- }
- }
- },
- onDismiss = viewModel::onUserCancel,
- )
-}
-
-@Composable
-fun PrimarySelectionCardGeneric(
- requestDisplayInfo: RequestDisplayInfo,
- providerDisplayInfo: ProviderDisplayInfo,
- providerInfoList: List<ProviderInfo>,
- onEntrySelected: (BaseEntry) -> Unit,
- onConfirm: () -> Unit,
- onLog: @Composable (UiEventLogger.UiEventEnum) -> Unit,
-) {
- val sortedUserNameToCredentialEntryList =
- providerDisplayInfo.sortedUserNameToCredentialEntryList
- val totalEntriesCount = sortedUserNameToCredentialEntryList
- .flatMap { it.sortedCredentialEntryList }.size
- SheetContainerCard {
- // When only one provider (not counting the remote-only provider) exists, display that
- // provider's icon + name up top.
- if (providerInfoList.size <= 2) { // It's only possible to be the single provider case
- // if we are started with no more than 2 providers.
- val nonRemoteProviderList = providerInfoList.filter(
- { it.credentialEntryList.isNotEmpty() || it.authenticationEntryList.isNotEmpty() }
- )
- if (nonRemoteProviderList.size == 1) {
- val providerInfo = nonRemoteProviderList.firstOrNull() // First should always work
- // but just to be safe.
- if (providerInfo != null) {
- item {
- HeadlineIcon(
- bitmap = providerInfo.icon.toBitmap().asImageBitmap(),
- tint = Color.Unspecified,
- )
- }
- item { Divider(thickness = 4.dp, color = Color.Transparent) }
- item { LargeLabelTextOnSurfaceVariant(text = providerInfo.displayName) }
- item { Divider(thickness = 16.dp, color = Color.Transparent) }
- }
- }
- }
-
- item {
- HeadlineText(
- text = stringResource(
- if (totalEntriesCount == 1) {
- R.string.get_dialog_title_use_info_on
- } else {
- R.string.get_dialog_title_choose_option_for
- },
- requestDisplayInfo.appName
- ),
- )
- }
- item { Divider(thickness = 24.dp, color = Color.Transparent) }
- item {
- CredentialContainerCard {
- Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
- sortedUserNameToCredentialEntryList.forEach {
- // TODO(b/275375861): fallback UI merges entries by account names.
- // Need a strategy to be able to show all entries.
- CredentialEntryRow(
- credentialEntryInfo = it.sortedCredentialEntryList.first(),
- onEntrySelected = onEntrySelected,
- enforceOneLine = true,
- )
- }
- }
- }
- }
- item { Divider(thickness = 24.dp, color = Color.Transparent) }
- item {
- if (totalEntriesCount == 1) {
- CtaButtonRow(
- rightButton = {
- ConfirmButton(
- stringResource(R.string.get_dialog_button_label_continue),
- onClick = onConfirm
- )
- }
- )
- }
- }
- }
- onLog(GetCredentialEvent.CREDMAN_GET_CRED_PRIMARY_SELECTION_CARD)
-}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
index a4a163b..716f474 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
@@ -41,10 +41,6 @@
!state.requestDisplayInfo.preferImmediatelyAvailableCredentials)
}
-internal fun isFallbackScreen(state: GetCredentialUiState): Boolean {
- return state.requestDisplayInfo.preferIdentityDocUi
-}
-
internal fun findAutoSelectEntry(providerDisplayInfo: ProviderDisplayInfo): CredentialEntryInfo? {
if (providerDisplayInfo.authenticationEntryList.isNotEmpty()) {
return null
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt
index 1786d13..91c0a5b 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt
@@ -19,17 +19,11 @@
val maxHeight: Float = 0f,
val pixelDensity: Float = 1f,
var color: Int = Color.WHITE,
- val opacity: Int = RIPPLE_DEFAULT_ALPHA,
- val sparkleStrength: Float = RIPPLE_SPARKLE_STRENGTH,
+ val opacity: Int = RippleShader.RIPPLE_DEFAULT_ALPHA,
+ val sparkleStrength: Float = RippleShader.RIPPLE_SPARKLE_STRENGTH,
// Null means it uses default fade parameter values.
val baseRingFadeParams: RippleShader.FadeParams? = null,
val sparkleRingFadeParams: RippleShader.FadeParams? = null,
val centerFillFadeParams: RippleShader.FadeParams? = null,
val shouldDistort: Boolean = true
-) {
- companion object {
- const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f
- const val RIPPLE_DEFAULT_COLOR: Int = 0xffffffff.toInt()
- const val RIPPLE_DEFAULT_ALPHA: Int = 115 // full opacity is 255.
- }
-}
+)
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt
index b5b6037..7e56f4b 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt
@@ -60,6 +60,10 @@
const val DEFAULT_CENTER_FILL_FADE_OUT_START = 0f
const val DEFAULT_CENTER_FILL_FADE_OUT_END = 0.6f
+ const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f
+ const val RIPPLE_DEFAULT_COLOR: Int = 0xffffffff.toInt()
+ const val RIPPLE_DEFAULT_ALPHA: Int = 115 // full opacity is 255.
+
private const val SHADER_UNIFORMS =
"""
uniform vec2 in_center;
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt
index ef5ad43..b899127 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt
@@ -72,9 +72,9 @@
this.rippleShape = rippleShape
rippleShader = RippleShader(rippleShape)
- rippleShader.color = RippleAnimationConfig.RIPPLE_DEFAULT_COLOR
+ rippleShader.color = RippleShader.RIPPLE_DEFAULT_COLOR
rippleShader.rawProgress = 0f
- rippleShader.sparkleStrength = RippleAnimationConfig.RIPPLE_SPARKLE_STRENGTH
+ rippleShader.sparkleStrength = RippleShader.RIPPLE_SPARKLE_STRENGTH
rippleShader.pixelDensity = resources.displayMetrics.density
ripplePaint.shader = rippleShader
@@ -209,7 +209,7 @@
*
* The alpha value of the color will be applied to the ripple. The alpha range is [0-255].
*/
- fun setColor(color: Int, alpha: Int = RippleAnimationConfig.RIPPLE_DEFAULT_ALPHA) {
+ fun setColor(color: Int, alpha: Int = RippleShader.RIPPLE_DEFAULT_ALPHA) {
rippleShader.color = ColorUtils.setAlphaComponent(color, alpha)
}
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt
index a5f832a..ff150c8c 100644
--- a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt
@@ -38,7 +38,7 @@
}
@Test
- fun `No violations`() {
+ fun noViolations() {
lint()
.files(
*LEGITIMATE_FILES,
@@ -51,7 +51,7 @@
}
@Test
- fun `Violation - domain depends on ui`() {
+ fun violation_domainDependsOnUi() {
lint()
.files(
*LEGITIMATE_FILES,
@@ -86,7 +86,7 @@
}
@Test
- fun `Violation - ui depends on data`() {
+ fun violation_uiDependsOnData() {
lint()
.files(
*LEGITIMATE_FILES,
@@ -121,7 +121,7 @@
}
@Test
- fun `Violation - shared depends on all other layers`() {
+ fun violation_sharedDependsOnAllOtherLayers() {
lint()
.files(
*LEGITIMATE_FILES,
@@ -166,7 +166,7 @@
}
@Test
- fun `Violation - data depends on domain`() {
+ fun violation_dataDependsOnDomain() {
lint()
.files(
*LEGITIMATE_FILES,
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index 3ec3b5c..6ca7f12 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -62,10 +62,7 @@
private val defaultLineSpacing = resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale)
override val events: DefaultClockEvents
- override lateinit var animations: DefaultClockAnimations
- private set
-
- override val config = ClockConfig(hasCustomPositionUpdatedAnimation = true)
+ override val config = ClockConfig()
init {
val parent = FrameLayout(ctx)
@@ -84,13 +81,13 @@
clocks = listOf(smallClock.view, largeClock.view)
events = DefaultClockEvents()
- animations = DefaultClockAnimations(0f, 0f)
events.onLocaleChanged(Locale.getDefault())
}
override fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) {
largeClock.recomputePadding(null)
- animations = DefaultClockAnimations(dozeFraction, foldFraction)
+ largeClock.animations = LargeClockAnimations(largeClock.view, dozeFraction, foldFraction)
+ smallClock.animations = DefaultClockAnimations(smallClock.view, dozeFraction, foldFraction)
events.onColorPaletteChanged(resources)
events.onTimeZoneChanged(TimeZone.getDefault())
smallClock.events.onTimeTick()
@@ -115,6 +112,9 @@
view.logBuffer = value
}
+ override var animations: DefaultClockAnimations = DefaultClockAnimations(view, 0f, 0f)
+ internal set
+
init {
if (seedColor != null) {
currentColor = seedColor!!
@@ -170,6 +170,12 @@
view: AnimatableClockView,
seedColor: Int?,
) : DefaultClockFaceController(view, seedColor) {
+ override val config = ClockFaceConfig(hasCustomPositionUpdatedAnimation = true)
+
+ init {
+ animations = LargeClockAnimations(view, 0f, 0f)
+ }
+
override fun recomputePadding(targetRegion: Rect?) {
// We center the view within the targetRegion instead of within the parent
// view by computing the difference and adding that to the padding.
@@ -220,7 +226,8 @@
}
}
- inner class DefaultClockAnimations(
+ open inner class DefaultClockAnimations(
+ val view: AnimatableClockView,
dozeFraction: Float,
foldFraction: Float,
) : ClockAnimations {
@@ -229,34 +236,40 @@
init {
if (foldState.isActive) {
- clocks.forEach { it.animateFoldAppear(false) }
+ view.animateFoldAppear(false)
} else {
- clocks.forEach { it.animateDoze(dozeState.isActive, false) }
+ view.animateDoze(dozeState.isActive, false)
}
}
override fun enter() {
if (!dozeState.isActive) {
- clocks.forEach { it.animateAppearOnLockscreen() }
+ view.animateAppearOnLockscreen()
}
}
- override fun charge() = clocks.forEach { it.animateCharge { dozeState.isActive } }
+ override fun charge() = view.animateCharge { dozeState.isActive }
override fun fold(fraction: Float) {
val (hasChanged, hasJumped) = foldState.update(fraction)
if (hasChanged) {
- clocks.forEach { it.animateFoldAppear(!hasJumped) }
+ view.animateFoldAppear(!hasJumped)
}
}
override fun doze(fraction: Float) {
val (hasChanged, hasJumped) = dozeState.update(fraction)
if (hasChanged) {
- clocks.forEach { it.animateDoze(dozeState.isActive, !hasJumped) }
+ view.animateDoze(dozeState.isActive, !hasJumped)
}
}
+ }
+ inner class LargeClockAnimations(
+ view: AnimatableClockView,
+ dozeFraction: Float,
+ foldFraction: Float,
+ ) : DefaultClockAnimations(view, dozeFraction, foldFraction) {
override fun onPositionUpdated(fromRect: Rect, toRect: Rect, fraction: Float) {
largeClock.moveForSplitShade(fromRect, toRect, fraction)
}
diff --git a/packages/SystemUI/docs/dagger.md b/packages/SystemUI/docs/dagger.md
index 9b4c21e..4a6240b 100644
--- a/packages/SystemUI/docs/dagger.md
+++ b/packages/SystemUI/docs/dagger.md
@@ -108,20 +108,13 @@
### Using injection with Fragments
-Fragments are created as part of the FragmentManager, so they need to be
-setup so the manager knows how to create them. To do that, add a method
-to com.android.systemui.fragments.FragmentService$FragmentCreator that
-returns your fragment class. That is all that is required, once the method
-exists, FragmentService will automatically pick it up and use injection
-whenever your fragment needs to be created.
+Fragments are created as part of the FragmentManager, so injectable Fragments need to be registered
+so the manager knows how to create them. This is done via
+[FragmentService#addFragmentInstantiationProvider](../src/com/android/systemui/fragments/FragmentService.java).
+Pass it the class of your fragment and a `Provider` for your fragment at some time before your
+Fragment is accessed.
-```java
-public interface FragmentCreator {
- NavigationBarFragment createNavigationBar();
-}
-```
-
-If you need to create your fragment (i.e. for the add or replace transaction),
+When you need to create your fragment (i.e. for the add or replace transaction),
then the FragmentHostManager can do this for you.
```java
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index 05630e7..8ef2d80 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -69,9 +69,6 @@
/** Events that clocks may need to respond to */
val events: ClockEvents
- /** Triggers for various animations */
- val animations: ClockAnimations
-
/** Initializes various rendering parameters. If never called, provides reasonable defaults. */
fun initialize(
resources: Resources,
@@ -79,8 +76,10 @@
foldFraction: Float,
) {
events.onColorPaletteChanged(resources)
- animations.doze(dozeFraction)
- animations.fold(foldFraction)
+ smallClock.animations.doze(dozeFraction)
+ largeClock.animations.doze(dozeFraction)
+ smallClock.animations.fold(foldFraction)
+ largeClock.animations.fold(foldFraction)
smallClock.events.onTimeTick()
largeClock.events.onTimeTick()
}
@@ -100,6 +99,9 @@
/** Events specific to this clock face */
val events: ClockFaceEvents
+ /** Triggers for various animations */
+ val animations: ClockAnimations
+
/** Some clocks may log debug information */
var logBuffer: LogBuffer?
}
@@ -192,13 +194,6 @@
/** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */
data class ClockConfig(
- /**
- * Whether this clock has a custom position update animation. If true, the keyguard will call
- * `onPositionUpdated` to notify the clock of a position update animation. If false, a default
- * animation will be used (e.g. a simple translation).
- */
- val hasCustomPositionUpdatedAnimation: Boolean = false,
-
/** Transition to AOD should move smartspace like large clock instead of small clock */
val useAlternateSmartspaceAODTransition: Boolean = false,
@@ -213,6 +208,13 @@
/** Call to check whether the clock consumes weather data */
val hasCustomWeatherDataDisplay: Boolean = false,
+
+ /**
+ * Whether this clock has a custom position update animation. If true, the keyguard will call
+ * `onPositionUpdated` to notify the clock of a position update animation. If false, a default
+ * animation will be used (e.g. a simple translation).
+ */
+ val hasCustomPositionUpdatedAnimation: Boolean = false,
)
/** Structure for keeping clock-specific settings */
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 10bb00c..a8ed843 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -1,156 +1,13 @@
-# Preserve line number information for debugging stack traces.
--keepattributes SourceFile,LineNumberTable
+-include proguard_common.flags
-# Preserve relationship information that can impact simple class naming.
--keepattributes EnclosingMethod,InnerClasses
-
--keep class com.android.systemui.recents.OverviewProxyRecentsImpl
--keep class com.android.systemui.statusbar.car.CarStatusBar
--keep class com.android.systemui.statusbar.phone.CentralSurfaces
-keep class com.android.systemui.statusbar.tv.TvStatusBar
--keep class ** extends com.android.systemui.SystemUIInitializer {
- *;
-}
--keep class * extends com.android.systemui.CoreStartable
--keep class * implements com.android.systemui.CoreStartable$Injector
-
-# Needed for builds to properly initialize KeyFrames from xml scene
--keepclassmembers class * extends androidx.constraintlayout.motion.widget.Key {
- public <init>();
-}
-
-# Needed to ensure callback field references are kept in their respective
-# owning classes when the downstream callback registrars only store weak refs.
-# TODO(b/264686688): Handle these cases with more targeted annotations.
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
- private com.android.keyguard.KeyguardUpdateMonitorCallback *;
- private com.android.systemui.privacy.PrivacyConfig$Callback *;
- private com.android.systemui.privacy.PrivacyItemController$Callback *;
- private com.android.systemui.settings.UserTracker$Callback *;
- private com.android.systemui.statusbar.phone.StatusBarWindowCallback *;
- private com.android.systemui.util.service.Observer$Callback *;
- private com.android.systemui.util.service.ObservableServiceConnection$Callback *;
-}
-# Note that these rules are temporary companions to the above rules, required
-# for cases like Kotlin where fields with anonymous types use the anonymous type
-# rather than the supertype.
--if class * extends com.android.keyguard.KeyguardUpdateMonitorCallback
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
- <1> *;
-}
--if class * extends com.android.systemui.privacy.PrivacyConfig$Callback
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
- <1> *;
-}
--if class * extends com.android.systemui.privacy.PrivacyItemController$Callback
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
- <1> *;
-}
--if class * extends com.android.systemui.settings.UserTracker$Callback
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
- <1> *;
-}
--if class * extends com.android.systemui.statusbar.phone.StatusBarWindowCallback
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
- <1> *;
-}
--if class * extends com.android.systemui.util.service.Observer$Callback
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
- <1> *;
-}
--if class * extends com.android.systemui.util.service.ObservableServiceConnection$Callback
--keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
- <1> *;
-}
-
--keepclasseswithmembers class * {
- public <init>(android.content.Context, android.util.AttributeSet);
-}
-
--keep class ** extends androidx.preference.PreferenceFragment
--keep class com.android.systemui.tuner.*
-
-# The plugins subpackage acts as a shared library that might be referenced in
-# dynamically-loaded plugin APKs.
--keep class com.android.systemui.plugins.** {
- *;
-}
--keep class com.android.systemui.fragments.FragmentService$FragmentCreator {
- *;
-}
--keep class androidx.core.app.CoreComponentFactory
-
--keep public class * extends com.android.systemui.CoreStartable {
- public <init>(android.content.Context);
-}
-
-# Keep the wm shell lib
--keep class com.android.wm.shell.*
-# Keep the protolog group methods that are called by the generated code
--keepclassmembers class com.android.wm.shell.protolog.ShellProtoLogGroup {
+-keep class com.android.systemui.SystemUIInitializerImpl {
*;
}
--keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.GlobalRootComponent { !synthetic *; }
--keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.GlobalRootComponent$SysUIComponentImpl { !synthetic *; }
--keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.Dagger** { !synthetic *; }
--keep,allowoptimization,allowaccessmodification class com.android.systemui.tv.Dagger** { !synthetic *; }
-
-# Prevent optimization or access modification of any referenced code that may
-# conflict with code in the bootclasspath.
-# TODO(b/222468116): Resolve such collisions in the build system.
--keepnames class android.**.nano.** { *; }
--keepnames class com.android.**.nano.** { *; }
--keepnames class com.android.internal.protolog.** { *; }
--keepnames class android.hardware.common.** { *; }
-
-# Allows proguard to make private and protected methods and fields public as
-# part of optimization. This lets proguard inline trivial getter/setter methods.
--allowaccessmodification
-
-# Removes runtime checks added through Kotlin to JVM code genereration to
-# avoid linear growth as more Kotlin code is converted / added to the codebase.
-# These checks are generally applied to Java platform types (values returned
-# from Java code that don't have nullness annotations), but we remove them to
-# avoid code size increases.
-#
-# See also https://kotlinlang.org/docs/reference/java-interop.html
-#
-# TODO(b/199941987): Consider standardizing these rules in a central place as
-# Kotlin gains adoption with other platform targets.
--assumenosideeffects class kotlin.jvm.internal.Intrinsics {
- # Remove check for method parameters being null
- static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
-
- # When a Java platform type is returned and passed to Kotlin NonNull method,
- # remove the null check
- static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String);
- static void checkNotNullExpressionValue(java.lang.Object, java.lang.String);
-
- # Remove check that final value returned from method is null, if passing
- # back Java platform type.
- static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
- static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String);
-
- # Null check for accessing a field from a parent class written in Java.
- static void checkFieldIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
- static void checkFieldIsNotNull(java.lang.Object, java.lang.String);
-
- # Removes code generated from !! operator which converts Nullable type to
- # NonNull type. These would throw an NPE immediate after on access.
- static void checkNotNull(java.lang.Object, java.lang.String);
- static void checkNotNullParameter(java.lang.Object, java.lang.String);
-
- # Removes lateinit var check being used before being set. Check is applied
- # on every field access without this.
- static void throwUninitializedPropertyAccessException(java.lang.String);
+-keep class com.android.systemui.tv.TvSystemUIInitializer {
+ *;
}
-# Strip verbose logs.
--assumenosideeffects class android.util.Log {
- static *** v(...);
- static *** isLoggable(...);
-}
--assumenosideeffects class android.util.Slog {
- static *** v(...);
-}
--maximumremovedandroidloglevel 2
+
+-keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.DaggerReferenceGlobalRootComponent** { !synthetic *; }
+-keep,allowoptimization,allowaccessmodification class com.android.systemui.tv.DaggerTvGlobalRootComponent** { !synthetic *; }
\ No newline at end of file
diff --git a/packages/SystemUI/proguard_common.flags b/packages/SystemUI/proguard_common.flags
new file mode 100644
index 0000000..1d008cf
--- /dev/null
+++ b/packages/SystemUI/proguard_common.flags
@@ -0,0 +1,141 @@
+# Preserve line number information for debugging stack traces.
+-keepattributes SourceFile,LineNumberTable
+
+-keep class com.android.systemui.VendorServices
+
+# the `#inject` methods are accessed via reflection to work on ContentProviders
+-keepclassmembers class * extends com.android.systemui.dagger.SysUIComponent { void inject(***); }
+
+# Needed for builds to properly initialize KeyFrames from xml scene
+-keepclassmembers class * extends androidx.constraintlayout.motion.widget.Key {
+ public <init>();
+}
+
+# Needed to ensure callback field references are kept in their respective
+# owning classes when the downstream callback registrars only store weak refs.
+# TODO(b/264686688): Handle these cases with more targeted annotations.
+-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
+ private com.android.keyguard.KeyguardUpdateMonitorCallback *;
+ private com.android.systemui.privacy.PrivacyConfig$Callback *;
+ private com.android.systemui.privacy.PrivacyItemController$Callback *;
+ private com.android.systemui.settings.UserTracker$Callback *;
+ private com.android.systemui.statusbar.phone.StatusBarWindowCallback *;
+ private com.android.systemui.util.service.Observer$Callback *;
+ private com.android.systemui.util.service.ObservableServiceConnection$Callback *;
+}
+# Note that these rules are temporary companions to the above rules, required
+# for cases like Kotlin where fields with anonymous types use the anonymous type
+# rather than the supertype.
+-if class * extends com.android.keyguard.KeyguardUpdateMonitorCallback
+-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
+ <1> *;
+}
+-if class * extends com.android.systemui.privacy.PrivacyConfig$Callback
+-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
+ <1> *;
+}
+-if class * extends com.android.systemui.privacy.PrivacyItemController$Callback
+-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
+ <1> *;
+}
+-if class * extends com.android.systemui.settings.UserTracker$Callback
+-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
+ <1> *;
+}
+-if class * extends com.android.systemui.statusbar.phone.StatusBarWindowCallback
+-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
+ <1> *;
+}
+-if class * extends com.android.systemui.util.service.Observer$Callback
+-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
+ <1> *;
+}
+-if class * extends com.android.systemui.util.service.ObservableServiceConnection$Callback
+-keepclassmembers,allowaccessmodification class com.android.systemui.**, com.android.keyguard.** {
+ <1> *;
+}
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keep class ** extends androidx.preference.PreferenceFragment
+-keep class com.android.systemui.tuner.*
+
+# The plugins subpackage acts as a shared library that might be referenced in
+# dynamically-loaded plugin APKs.
+-keep class com.android.systemui.plugins.** {
+ *;
+}
+-keep class com.android.systemui.fragments.FragmentService$FragmentCreator {
+ *;
+}
+-keep class androidx.core.app.CoreComponentFactory
+
+# Keep the wm shell lib
+-keep class com.android.wm.shell.*
+# Keep the protolog group methods that are called by the generated code
+-keepclassmembers class com.android.wm.shell.protolog.ShellProtoLogGroup {
+ *;
+}
+
+# Prevent optimization or access modification of any referenced code that may
+# conflict with code in the bootclasspath.
+# TODO(b/222468116): Resolve such collisions in the build system.
+-keepnames class android.**.nano.** { *; }
+-keepnames class com.android.**.nano.** { *; }
+-keepnames class com.android.internal.protolog.** { *; }
+-keepnames class android.hardware.common.** { *; }
+
+# Allows proguard to make private and protected methods and fields public as
+# part of optimization. This lets proguard inline trivial getter/setter methods.
+-allowaccessmodification
+
+# Removes runtime checks added through Kotlin to JVM code genereration to
+# avoid linear growth as more Kotlin code is converted / added to the codebase.
+# These checks are generally applied to Java platform types (values returned
+# from Java code that don't have nullness annotations), but we remove them to
+# avoid code size increases.
+#
+# See also https://kotlinlang.org/docs/reference/java-interop.html
+#
+# TODO(b/199941987): Consider standardizing these rules in a central place as
+# Kotlin gains adoption with other platform targets.
+-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
+ # Remove check for method parameters being null
+ static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
+
+ # When a Java platform type is returned and passed to Kotlin NonNull method,
+ # remove the null check
+ static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String);
+ static void checkNotNullExpressionValue(java.lang.Object, java.lang.String);
+
+ # Remove check that final value returned from method is null, if passing
+ # back Java platform type.
+ static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
+ static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String);
+
+ # Null check for accessing a field from a parent class written in Java.
+ static void checkFieldIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
+ static void checkFieldIsNotNull(java.lang.Object, java.lang.String);
+
+ # Removes code generated from !! operator which converts Nullable type to
+ # NonNull type. These would throw an NPE immediate after on access.
+ static void checkNotNull(java.lang.Object, java.lang.String);
+ static void checkNotNullParameter(java.lang.Object, java.lang.String);
+
+ # Removes lateinit var check being used before being set. Check is applied
+ # on every field access without this.
+ static void throwUninitializedPropertyAccessException(java.lang.String);
+}
+
+
+# Strip verbose logs.
+-assumenosideeffects class android.util.Log {
+ static *** v(...);
+ static *** isLoggable(...);
+}
+-assumenosideeffects class android.util.Slog {
+ static *** v(...);
+}
+-maximumremovedandroidloglevel 2
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 26502f1..bbac7b0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2467,7 +2467,7 @@
<!-- Controls management controls screen default title [CHAR LIMIT=30] -->
<string name="controls_favorite_default_title">Controls</string>
<!-- Controls management controls screen subtitle [CHAR LIMIT=NONE] -->
- <string name="controls_favorite_subtitle">Choose controls to access from Quick Settings</string>
+ <string name="controls_favorite_subtitle">Choose device controls to access quickly</string>
<!-- Controls management editing screen, user direction for rearranging controls [CHAR LIMIT=NONE] -->
<string name="controls_favorite_rearrange">Hold & drag to rearrange controls</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 7262a73..8b87e2a 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -99,8 +99,10 @@
value.initialize(resources, dozeAmount, 0f)
if (regionSamplingEnabled) {
- clock?.smallClock?.view?.addOnLayoutChangeListener(mLayoutChangedListener)
- clock?.largeClock?.view?.addOnLayoutChangeListener(mLayoutChangedListener)
+ clock?.run {
+ smallClock.view.addOnLayoutChangeListener(mLayoutChangedListener)
+ largeClock.view.addOnLayoutChangeListener(mLayoutChangedListener)
+ }
} else {
updateColors()
}
@@ -175,15 +177,17 @@
private fun updateColors() {
val wallpaperManager = WallpaperManager.getInstance(context)
if (regionSamplingEnabled && !wallpaperManager.lockScreenWallpaperExists()) {
- if (regionSampler != null) {
- if (regionSampler?.sampledView == clock?.smallClock?.view) {
- smallClockIsDark = regionSampler!!.currentRegionDarkness().isDark
- clock?.smallClock?.events?.onRegionDarknessChanged(smallClockIsDark)
- return
- } else if (regionSampler?.sampledView == clock?.largeClock?.view) {
- largeClockIsDark = regionSampler!!.currentRegionDarkness().isDark
- clock?.largeClock?.events?.onRegionDarknessChanged(largeClockIsDark)
- return
+ regionSampler?.let { regionSampler ->
+ clock?.let { clock ->
+ if (regionSampler.sampledView == clock.smallClock.view) {
+ smallClockIsDark = regionSampler.currentRegionDarkness().isDark
+ clock.smallClock.events.onRegionDarknessChanged(smallClockIsDark)
+ return@updateColors
+ } else if (regionSampler.sampledView == clock.largeClock.view) {
+ largeClockIsDark = regionSampler.currentRegionDarkness().isDark
+ clock.largeClock.events.onRegionDarknessChanged(largeClockIsDark)
+ return@updateColors
+ }
}
}
}
@@ -193,8 +197,10 @@
smallClockIsDark = isLightTheme.data == 0
largeClockIsDark = isLightTheme.data == 0
- clock?.smallClock?.events?.onRegionDarknessChanged(smallClockIsDark)
- clock?.largeClock?.events?.onRegionDarknessChanged(largeClockIsDark)
+ clock?.run {
+ smallClock.events.onRegionDarknessChanged(smallClockIsDark)
+ largeClock.events.onRegionDarknessChanged(largeClockIsDark)
+ }
}
private fun updateRegionSampler(sampledRegion: View) {
@@ -240,7 +246,7 @@
private val configListener =
object : ConfigurationController.ConfigurationListener {
override fun onThemeChanged() {
- clock?.events?.onColorPaletteChanged(resources)
+ clock?.run { events.onColorPaletteChanged(resources) }
updateColors()
}
@@ -253,7 +259,10 @@
object : BatteryStateChangeCallback {
override fun onBatteryLevelChanged(level: Int, pluggedIn: Boolean, charging: Boolean) {
if (isKeyguardVisible && !isCharging && charging) {
- clock?.animations?.charge()
+ clock?.run {
+ smallClock.animations.charge()
+ largeClock.animations.charge()
+ }
}
isCharging = charging
}
@@ -262,7 +271,7 @@
private val localeBroadcastReceiver =
object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
- clock?.events?.onLocaleChanged(Locale.getDefault())
+ clock?.run { events.onLocaleChanged(Locale.getDefault()) }
}
}
@@ -272,7 +281,10 @@
isKeyguardVisible = visible
if (!featureFlags.isEnabled(DOZING_MIGRATION_1)) {
if (!isKeyguardVisible) {
- clock?.animations?.doze(if (isDozing) 1f else 0f)
+ clock?.run {
+ smallClock.animations.doze(if (isDozing) 1f else 0f)
+ largeClock.animations.doze(if (isDozing) 1f else 0f)
+ }
}
}
@@ -281,19 +293,19 @@
}
override fun onTimeFormatChanged(timeFormat: String?) {
- clock?.events?.onTimeFormatChanged(DateFormat.is24HourFormat(context))
+ clock?.run { events.onTimeFormatChanged(DateFormat.is24HourFormat(context)) }
}
override fun onTimeZoneChanged(timeZone: TimeZone) {
- clock?.events?.onTimeZoneChanged(timeZone)
+ clock?.run { events.onTimeZoneChanged(timeZone) }
}
override fun onUserSwitchComplete(userId: Int) {
- clock?.events?.onTimeFormatChanged(DateFormat.is24HourFormat(context))
+ clock?.run { events.onTimeFormatChanged(DateFormat.is24HourFormat(context)) }
}
override fun onWeatherDataChanged(data: WeatherData) {
- clock?.events?.onWeatherDataChanged(data)
+ clock?.run { events.onWeatherDataChanged(data) }
}
}
@@ -349,34 +361,33 @@
smallTimeListener = null
largeTimeListener = null
- clock?.smallClock?.let {
- smallTimeListener = TimeListener(it, mainExecutor)
- smallTimeListener?.update(shouldTimeListenerRun)
- }
- clock?.largeClock?.let {
- largeTimeListener = TimeListener(it, mainExecutor)
- largeTimeListener?.update(shouldTimeListenerRun)
+ clock?.let {
+ smallTimeListener = TimeListener(it.smallClock, mainExecutor).apply {
+ update(shouldTimeListenerRun)
+ }
+ largeTimeListener = TimeListener(it.largeClock, mainExecutor).apply {
+ update(shouldTimeListenerRun)
+ }
}
}
private fun updateFontSizes() {
- clock
- ?.smallClock
- ?.events
- ?.onFontSettingChanged(
+ clock?.run {
+ smallClock.events.onFontSettingChanged(
resources.getDimensionPixelSize(R.dimen.small_clock_text_size).toFloat()
)
- clock
- ?.largeClock
- ?.events
- ?.onFontSettingChanged(
+ largeClock.events.onFontSettingChanged(
resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat()
)
+ }
}
private fun handleDoze(doze: Float) {
dozeAmount = doze
- clock?.animations?.doze(dozeAmount)
+ clock?.run {
+ smallClock.animations.doze(dozeAmount)
+ largeClock.animations.doze(dozeAmount)
+ }
smallTimeListener?.update(doze < DOZE_TICKRATE_THRESHOLD)
largeTimeListener?.update(doze < DOZE_TICKRATE_THRESHOLD)
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 5ba0ad6..a6c782d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -26,8 +26,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import kotlin.Unit;
-
/**
* Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
*/
@@ -38,6 +36,8 @@
private static final long CLOCK_OUT_MILLIS = 150;
private static final long CLOCK_IN_MILLIS = 200;
+ public static final long CLOCK_IN_START_DELAY_MILLIS = CLOCK_OUT_MILLIS / 2;
+ private static final long STATUS_AREA_START_DELAY_MILLIS = 50;
private static final long STATUS_AREA_MOVE_MILLIS = 350;
@IntDef({LARGE, SMALL})
@@ -173,7 +173,7 @@
msg.setBool1(useLargeClock);
msg.setBool2(animate);
msg.setBool3(mChildrenAreLaidOut);
- return Unit.INSTANCE;
+ return kotlin.Unit.INSTANCE;
}, (msg) -> "updateClockViews"
+ "; useLargeClock=" + msg.getBool1()
+ "; animate=" + msg.getBool2()
@@ -235,7 +235,7 @@
mClockInAnim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
mClockInAnim.playTogether(ObjectAnimator.ofFloat(in, View.ALPHA, 1f),
ObjectAnimator.ofFloat(in, View.TRANSLATION_Y, direction * mClockSwitchYAmount, 0));
- mClockInAnim.setStartDelay(CLOCK_OUT_MILLIS / 2);
+ mClockInAnim.setStartDelay(CLOCK_IN_START_DELAY_MILLIS);
mClockInAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
mClockInAnim = null;
@@ -247,6 +247,7 @@
mStatusAreaAnim = ObjectAnimator.ofFloat(mStatusArea, View.TRANSLATION_Y,
statusAreaYTranslation);
+ mStatusAreaAnim.setStartDelay(useLargeClock ? STATUS_AREA_START_DELAY_MILLIS : 0L);
mStatusAreaAnim.setDuration(STATUS_AREA_MOVE_MILLIS);
mStatusAreaAnim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mStatusAreaAnim.addListener(new AnimatorListenerAdapter() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index ad333b7..a34c9fa 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -53,11 +53,11 @@
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.util.ViewController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.settings.SecureSettings;
import java.io.PrintWriter;
import java.util.Locale;
-import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -98,7 +98,7 @@
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private boolean mOnlyClock = false;
- private final Executor mUiExecutor;
+ private final DelayableExecutor mUiExecutor;
private boolean mCanShowDoubleLineClock = true;
private final ContentObserver mDoubleLineClockObserver = new ContentObserver(null) {
@Override
@@ -133,7 +133,7 @@
LockscreenSmartspaceController smartspaceController,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
SecureSettings secureSettings,
- @Main Executor uiExecutor,
+ @Main DelayableExecutor uiExecutor,
DumpManager dumpManager,
ClockEventController clockEventController,
@KeyguardClockLog LogBuffer logBuffer) {
@@ -344,7 +344,8 @@
ClockController clock = getClock();
boolean appeared = mView.switchToClock(clockSize, animate);
if (clock != null && animate && appeared && clockSize == LARGE) {
- clock.getAnimations().enter();
+ mUiExecutor.executeDelayed(() -> clock.getLargeClock().getAnimations().enter(),
+ KeyguardClockSwitch.CLOCK_IN_START_DELAY_MILLIS);
}
}
@@ -354,7 +355,8 @@
public void animateFoldToAod(float foldFraction) {
ClockController clock = getClock();
if (clock != null) {
- clock.getAnimations().fold(foldFraction);
+ clock.getSmallClock().getAnimations().fold(foldFraction);
+ clock.getLargeClock().getAnimations().fold(foldFraction);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 0cdef4d..edfcb8d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -349,7 +349,7 @@
ClockController clock = mKeyguardClockSwitchController.getClock();
boolean customClockAnimation = clock != null
- && clock.getConfig().getHasCustomPositionUpdatedAnimation();
+ && clock.getLargeClock().getConfig().getHasCustomPositionUpdatedAnimation();
if (mFeatureFlags.isEnabled(Flags.STEP_CLOCK_ANIMATION) && customClockAnimation) {
// Find the clock, so we can exclude it from this transition.
@@ -436,7 +436,8 @@
return;
}
- clock.getAnimations().onPositionUpdated(from, to, animation.getAnimatedFraction());
+ clock.getLargeClock().getAnimations()
+ .onPositionUpdated(from, to, animation.getAnimatedFraction());
});
return anim;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index c48aaf4..ea04376 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1771,10 +1771,6 @@
MSG_TIMEZONE_UPDATE, intent.getStringExtra(Intent.EXTRA_TIMEZONE));
mHandler.sendMessage(msg);
} else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
- // Clear incompatible charger state when device is unplugged.
- if (!BatteryStatus.isPluggedIn(intent)) {
- mIncompatibleCharger = false;
- }
final Message msg = mHandler.obtainMessage(
MSG_BATTERY_UPDATE, new BatteryStatus(intent, mIncompatibleCharger));
mHandler.sendMessage(msg);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
index b6ee4cb..3349fe5 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.util.Range;
+import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
@@ -68,14 +69,18 @@
@NonNull Callback settingsControllerCallback,
SecureSettings secureSettings,
WindowMagnificationSettings windowMagnificationSettings) {
- mContext = context;
+ mContext = context.createWindowContext(
+ context.getDisplay(),
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ null);
+ mContext.setTheme(com.android.systemui.R.style.Theme_SystemUI);
mDisplayId = mContext.getDisplayId();
- mConfiguration = new Configuration(context.getResources().getConfiguration());
+ mConfiguration = new Configuration(mContext.getResources().getConfiguration());
mSettingsControllerCallback = settingsControllerCallback;
if (windowMagnificationSettings != null) {
mWindowMagnificationSettings = windowMagnificationSettings;
} else {
- mWindowMagnificationSettings = new WindowMagnificationSettings(context,
+ mWindowMagnificationSettings = new WindowMagnificationSettings(mContext,
mWindowMagnificationSettingsCallback,
sfVsyncFrameProvider, secureSettings);
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
index 71c5f24..6e8275f 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
@@ -559,7 +559,7 @@
final LayoutParams params = new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT,
- LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY,
+ LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSPARENT);
params.gravity = Gravity.TOP | Gravity.START;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index f435b22..aeebb01 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -880,7 +880,7 @@
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL,
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
windowFlags,
PixelFormat.TRANSLUCENT);
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index 98a3e4b..11ef749 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -34,7 +34,6 @@
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.shared.recents.utilities.Utilities;
-import com.android.systemui.surfaceeffects.ripple.RippleAnimationConfig;
import com.android.systemui.surfaceeffects.ripple.RippleShader;
import com.android.systemui.surfaceeffects.ripple.RippleShader.RippleShape;
import com.android.systemui.surfaceeffects.ripple.RippleView;
@@ -177,7 +176,7 @@
mRippleView.setBlur(6.5f, 2.5f);
} else {
mRippleView.setDuration(CIRCLE_RIPPLE_ANIMATION_DURATION);
- mRippleView.setColor(color, RippleAnimationConfig.RIPPLE_DEFAULT_ALPHA);
+ mRippleView.setColor(color, RippleShader.RIPPLE_DEFAULT_ALPHA);
}
OnAttachStateChangeListener listener = new OnAttachStateChangeListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index 5230159..0aeab10 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -32,7 +32,6 @@
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TAP_OUTSIDE;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TIMED_OUT;
-import static com.android.systemui.flags.Flags.CLIPBOARD_REMOTE_BEHAVIOR;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -277,7 +276,7 @@
} else if (!mIsMinimized) {
setExpandedView();
}
- if (mFeatureFlags.isEnabled(CLIPBOARD_REMOTE_BEHAVIOR) && mClipboardModel.isRemote()) {
+ if (mClipboardModel.isRemote()) {
mTimeoutHandler.cancelTimeout();
mOnUiUpdate = null;
} else {
@@ -291,8 +290,7 @@
mView.setMinimized(false);
switch (model.getType()) {
case TEXT:
- if ((mFeatureFlags.isEnabled(CLIPBOARD_REMOTE_BEHAVIOR) && model.isRemote())
- || DeviceConfig.getBoolean(
+ if (model.isRemote() || DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_SHOW_ACTIONS, false)) {
if (model.getTextLinks() != null) {
classifyText(model);
@@ -326,11 +324,7 @@
mView.showDefaultTextPreview();
break;
}
- if (mFeatureFlags.isEnabled(CLIPBOARD_REMOTE_BEHAVIOR)) {
- if (!model.isRemote()) {
- maybeShowRemoteCopy(model.getClipData());
- }
- } else {
+ if (!model.isRemote()) {
maybeShowRemoteCopy(model.getClipData());
}
if (model.getType() != ClipboardModel.Type.OTHER) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 044dd6a..75f70ae 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -48,7 +48,6 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.FlagsModule;
-import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyboard.KeyboardModule;
import com.android.systemui.keyguard.data.BouncerViewModule;
import com.android.systemui.log.dagger.LogModule;
@@ -64,6 +63,7 @@
import com.android.systemui.qrcodescanner.dagger.QRCodeScannerModule;
import com.android.systemui.qs.FgsManagerController;
import com.android.systemui.qs.FgsManagerControllerImpl;
+import com.android.systemui.qs.QSFragmentStartableModule;
import com.android.systemui.qs.footer.dagger.FooterActionsModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.screenrecord.ScreenRecordModule;
@@ -169,6 +169,7 @@
PolicyModule.class,
PrivacyModule.class,
QRCodeScannerModule.class,
+ QSFragmentStartableModule.class,
ScreenshotModule.class,
SensorModule.class,
SecurityRepositoryModule.class,
@@ -198,8 +199,7 @@
DozeComponent.class,
ExpandableNotificationRowComponent.class,
KeyguardBouncerComponent.class,
- NotificationShelfComponent.class,
- FragmentService.FragmentCreator.class
+ NotificationShelfComponent.class
})
public abstract class SystemUIModule {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 8783ec3..29c63bb 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -72,7 +72,7 @@
@JvmField
val SIMPLIFIED_APPEAR_FRACTION =
- unreleasedFlag(259395680, "simplified_appear_fraction", teamfood = true)
+ releasedFlag(259395680, "simplified_appear_fraction")
// TODO(b/257315550): Tracking Bug
val NO_HUN_FOR_OLD_WHEN = releasedFlag(118, "no_hun_for_old_when")
@@ -383,7 +383,7 @@
val MEDIA_RETAIN_RECOMMENDATIONS = releasedFlag(916, "media_retain_recommendations")
// TODO(b/270437894): Tracking Bug
- val MEDIA_REMOTE_RESUME = unreleasedFlag(917, "media_remote_resume", teamfood = true)
+ val MEDIA_REMOTE_RESUME = releasedFlag(917, "media_remote_resume")
// 1000 - dock
val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag(1000, "simulate_dock_through_charging")
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index 6a27ee7..81a5206 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -39,16 +39,17 @@
import com.android.systemui.plugins.Plugin;
import com.android.systemui.util.leak.LeakDetector;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.HashMap;
-
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
import dagger.assisted.AssistedInject;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.inject.Provider;
+
public class FragmentHostManager {
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -322,25 +323,17 @@
return instantiateWithInjections(context, className, arguments);
}
- private Fragment instantiateWithInjections(
- Context context, String className, Bundle args) {
- FragmentService.FragmentInstantiationInfo fragmentInstantiationInfo =
+ private Fragment instantiateWithInjections(Context context, String className, Bundle args) {
+ Provider<? extends Fragment> fragmentProvider =
mManager.getInjectionMap().get(className);
- if (fragmentInstantiationInfo != null) {
- try {
- Fragment f = (Fragment) fragmentInstantiationInfo
- .mMethod
- .invoke(fragmentInstantiationInfo.mDaggerComponent);
- // Setup the args, taken from Fragment#instantiate.
- if (args != null) {
- args.setClassLoader(f.getClass().getClassLoader());
- f.setArguments(args);
- }
- return f;
- } catch (IllegalAccessException | InvocationTargetException e) {
- throw new Fragment.InstantiationException("Unable to instantiate " + className,
- e);
+ if (fragmentProvider != null) {
+ Fragment f = fragmentProvider.get();
+ // Setup the args, taken from Fragment#instantiate.
+ if (args != null) {
+ args.setClassLoader(f.getClass().getClassLoader());
+ f.setArguments(args);
}
+ return f;
}
return Fragment.instantiate(context, className, args);
}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
index d302b13a..a75c056 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
@@ -24,16 +24,12 @@
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.qs.QSFragment;
import com.android.systemui.statusbar.policy.ConfigurationController;
import java.io.PrintWriter;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import javax.inject.Inject;
-
-import dagger.Subcomponent;
+import javax.inject.Provider;
/**
* Holds a map of root views to FragmentHostStates and generates them as needed.
@@ -49,9 +45,9 @@
* A map with the means to create fragments via Dagger injection.
*
* key: the fragment class name.
- * value: see {@link FragmentInstantiationInfo}.
+ * value: A {@link Provider} for the Fragment
*/
- private final ArrayMap<String, FragmentInstantiationInfo> mInjectionMap = new ArrayMap<>();
+ private final ArrayMap<String, Provider<? extends Fragment>> mInjectionMap = new ArrayMap<>();
private final Handler mHandler = new Handler();
private final FragmentHostManager.Factory mFragmentHostManagerFactory;
@@ -67,38 +63,31 @@
@Inject
public FragmentService(
- FragmentCreator.Factory fragmentCreatorFactory,
FragmentHostManager.Factory fragmentHostManagerFactory,
ConfigurationController configurationController,
DumpManager dumpManager) {
mFragmentHostManagerFactory = fragmentHostManagerFactory;
- addFragmentInstantiationProvider(fragmentCreatorFactory.build());
configurationController.addCallback(mConfigurationListener);
- dumpManager.registerDumpable(getClass().getSimpleName(), this);
+ dumpManager.registerNormalDumpable(this);
}
- ArrayMap<String, FragmentInstantiationInfo> getInjectionMap() {
+ ArrayMap<String, Provider<? extends Fragment>> getInjectionMap() {
return mInjectionMap;
}
/**
* Adds a new Dagger component object that provides method(s) to create fragments via injection.
*/
- public void addFragmentInstantiationProvider(Object daggerComponent) {
- for (Method method : daggerComponent.getClass().getDeclaredMethods()) {
- if (Fragment.class.isAssignableFrom(method.getReturnType())
- && (method.getModifiers() & Modifier.PUBLIC) != 0) {
- String fragmentName = method.getReturnType().getName();
- if (mInjectionMap.containsKey(fragmentName)) {
- Log.w(TAG, "Fragment " + fragmentName + " is already provided by different"
- + " Dagger component; Not adding method");
- continue;
- }
- mInjectionMap.put(
- fragmentName, new FragmentInstantiationInfo(method, daggerComponent));
- }
+ public void addFragmentInstantiationProvider(
+ Class<?> fragmentCls, Provider<? extends Fragment> provider) {
+ String fragmentName = fragmentCls.getName();
+ if (mInjectionMap.containsKey(fragmentName)) {
+ Log.w(TAG, "Fragment " + fragmentName + " is already provided by different"
+ + " Dagger component; Not adding method");
+ return;
}
+ mInjectionMap.put(fragmentName, provider);
}
public FragmentHostManager getFragmentHostManager(View view) {
@@ -132,22 +121,6 @@
}
}
- /**
- * The subcomponent of dagger that holds all fragments that need injection.
- */
- @Subcomponent
- public interface FragmentCreator {
- /** Factory for creating a FragmentCreator. */
- @Subcomponent.Factory
- interface Factory {
- FragmentCreator build();
- }
- /**
- * Inject a QSFragment.
- */
- QSFragment createQSFragment();
- }
-
private class FragmentHostState {
private final View mView;
@@ -170,16 +143,4 @@
mFragmentHostManager.onConfigurationChanged(newConfig);
}
}
-
- /** An object containing the information needed to instantiate a fragment. */
- static class FragmentInstantiationInfo {
- /** The method that returns a newly-created fragment of the given class. */
- final Method mMethod;
- /** The Dagger component that the method should be invoked on. */
- final Object mDaggerComponent;
- FragmentInstantiationInfo(Method method, Object daggerComponent) {
- this.mMethod = method;
- this.mDaggerComponent = daggerComponent;
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index 5f6098b..05ab01b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -140,8 +140,10 @@
private var authCancellationSignal: CancellationSignal? = null
private var detectCancellationSignal: CancellationSignal? = null
private var faceAcquiredInfoIgnoreList: Set<Int>
+ private var retryCount = 0
private var cancelNotReceivedHandlerJob: Job? = null
+ private var halErrorRetryJob: Job? = null
private val _authenticationStatus: MutableStateFlow<AuthenticationStatus?> =
MutableStateFlow(null)
@@ -228,6 +230,8 @@
.onEach { goingAwayOrUserSwitchingInProgress ->
if (goingAwayOrUserSwitchingInProgress) {
_isAuthenticated.value = false
+ retryCount = 0
+ halErrorRetryJob?.cancel()
}
}
.launchIn(applicationScope)
@@ -385,14 +389,11 @@
_authenticationStatus.value = errorStatus
_isAuthenticated.value = false
if (errorStatus.isCancellationError()) {
- cancelNotReceivedHandlerJob?.cancel()
- applicationScope.launch {
- faceAuthLogger.launchingQueuedFaceAuthRequest(
- faceAuthRequestedWhileCancellation
- )
- faceAuthRequestedWhileCancellation?.let { authenticate(it) }
- faceAuthRequestedWhileCancellation = null
- }
+ handleFaceCancellationError()
+ }
+ if (errorStatus.isHardwareError()) {
+ faceAuthLogger.hardwareError(errorStatus)
+ handleFaceHardwareError()
}
faceAuthLogger.authenticationError(
errorCode,
@@ -418,6 +419,35 @@
}
}
+ private fun handleFaceCancellationError() {
+ cancelNotReceivedHandlerJob?.cancel()
+ applicationScope.launch {
+ faceAuthRequestedWhileCancellation?.let {
+ faceAuthLogger.launchingQueuedFaceAuthRequest(it)
+ authenticate(it)
+ }
+ faceAuthRequestedWhileCancellation = null
+ }
+ }
+
+ private fun handleFaceHardwareError() {
+ if (retryCount < HAL_ERROR_RETRY_MAX) {
+ retryCount++
+ halErrorRetryJob?.cancel()
+ halErrorRetryJob =
+ applicationScope.launch {
+ delay(HAL_ERROR_RETRY_TIMEOUT)
+ if (retryCount < HAL_ERROR_RETRY_MAX) {
+ faceAuthLogger.attemptingRetryAfterHardwareError(retryCount)
+ authenticate(
+ FaceAuthUiEvent.FACE_AUTH_TRIGGERED_RETRY_AFTER_HW_UNAVAILABLE,
+ fallbackToDetection = false
+ )
+ }
+ }
+ }
+ }
+
private fun onFaceAuthRequestCompleted() {
cancellationInProgress = false
_isAuthRunning.value = false
@@ -558,6 +588,12 @@
* cancelled.
*/
const val DEFAULT_CANCEL_SIGNAL_TIMEOUT = 3000L
+
+ /** Number of allowed retries whenever there is a face hardware error */
+ const val HAL_ERROR_RETRY_MAX = 20
+
+ /** Timeout before retries whenever there is a HAL error. */
+ const val HAL_ERROR_RETRY_TIMEOUT = 500L // ms
}
override fun dump(pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt
index eded9c1..c8bd958 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt
@@ -50,6 +50,11 @@
* was cancelled before it completed.
*/
fun isCancellationError() = msgId == FaceManager.FACE_ERROR_CANCELED
+
+ /** Method that checks if [msgId] is a hardware error. */
+ fun isHardwareError() =
+ msgId == FaceManager.FACE_ERROR_HW_UNAVAILABLE ||
+ msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS
}
/** Face detection success message. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
index 5770f3e..ddce516 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
@@ -47,6 +47,7 @@
duration = TO_LOCKSCREEN_DURATION,
onStep = { value -> -translatePx + value * translatePx },
interpolator = EMPHASIZED_DECELERATE,
+ onCancel = { 0f },
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
index 7f6e4a9..efd3ad6 100644
--- a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
@@ -4,6 +4,7 @@
import android.hardware.face.FaceSensorPropertiesInternal
import com.android.keyguard.FaceAuthUiEvent
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.log.dagger.FaceAuthLog
import com.android.systemui.plugins.log.LogBuffer
@@ -239,4 +240,25 @@
{ "Requesting face auth for trigger: $str1" }
)
}
+
+ fun hardwareError(errorStatus: ErrorAuthenticationStatus) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = "${errorStatus.msg}"
+ int1 = errorStatus.msgId
+ },
+ { "Received face hardware error: $str1 , code: $int1" }
+ )
+ }
+
+ fun attemptingRetryAfterHardwareError(retryCount: Int) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { int1 = retryCount },
+ { "Attempting face auth again because of HW error: retry attempt $int1" }
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 8f70376..aab898e 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -85,12 +85,12 @@
fun onBubbleExpandChanged(isExpanding: Boolean, key: String?) {
if (!isEnabled) return
- if (key != Bubble.KEY_APP_BUBBLE) return
+ val info = infoReference.getAndSet(null) ?: return
- val info = infoReference.getAndSet(null)
+ if (key != Bubble.getAppBubbleKeyForApp(info.packageName, info.user)) return
// Safe guard mechanism, this callback should only be called for app bubbles.
- if (info?.launchMode != NoteTaskLaunchMode.AppBubble) return
+ if (info.launchMode != NoteTaskLaunchMode.AppBubble) return
if (isExpanding) {
logDebug { "onBubbleExpandChanged - expanding: $info" }
@@ -173,7 +173,7 @@
return
}
- val info = resolver.resolveInfo(entryPoint, isKeyguardLocked)
+ val info = resolver.resolveInfo(entryPoint, isKeyguardLocked, user)
if (info == null) {
logDebug { "Default notes app isn't set" }
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt
index 2b9f0af..a758347 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt
@@ -15,10 +15,13 @@
*/
package com.android.systemui.notetask
+import android.os.UserHandle
+
/** Contextual information required to launch a Note Task by [NoteTaskController]. */
data class NoteTaskInfo(
val packageName: String,
val uid: Int,
+ val user: UserHandle,
val entryPoint: NoteTaskEntryPoint? = null,
val isKeyguardLocked: Boolean = false,
) {
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfoResolver.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfoResolver.kt
index 616f9b5..89a8526 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfoResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfoResolver.kt
@@ -25,7 +25,6 @@
import android.os.UserHandle
import android.util.Log
import com.android.systemui.notetask.NoteTaskRoleManagerExt.getDefaultRoleHolderAsUser
-import com.android.systemui.settings.UserTracker
import javax.inject.Inject
class NoteTaskInfoResolver
@@ -33,15 +32,13 @@
constructor(
private val roleManager: RoleManager,
private val packageManager: PackageManager,
- private val userTracker: UserTracker,
) {
fun resolveInfo(
entryPoint: NoteTaskEntryPoint? = null,
isKeyguardLocked: Boolean = false,
+ user: UserHandle,
): NoteTaskInfo? {
- val user = userTracker.userHandle
-
val packageName = roleManager.getDefaultRoleHolderAsUser(ROLE_NOTES, user)
if (packageName.isNullOrEmpty()) return null
@@ -49,6 +46,7 @@
return NoteTaskInfo(
packageName = packageName,
uid = packageManager.getUidOf(packageName, user),
+ user = user,
entryPoint = entryPoint,
isKeyguardLocked = isKeyguardLocked,
)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentStartable.kt b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentStartable.kt
new file mode 100644
index 0000000..253560b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentStartable.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.fragments.FragmentService
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import javax.inject.Inject
+import javax.inject.Provider
+
+@SysUISingleton
+class QSFragmentStartable
+@Inject
+constructor(
+ private val fragmentService: FragmentService,
+ private val qsFragmentProvider: Provider<QSFragment>
+) : CoreStartable {
+ override fun start() {
+ fragmentService.addFragmentInstantiationProvider(QSFragment::class.java, qsFragmentProvider)
+ }
+}
+
+@Module
+interface QSFragmentStartableModule {
+ @Binds
+ @IntoMap
+ @ClassKey(QSFragmentStartable::class)
+ fun bindsQSFragmentStartable(startable: QSFragmentStartable): CoreStartable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 72ae16e..1714f48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -71,6 +71,8 @@
import com.android.systemui.util.Utils;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import dagger.Lazy;
+
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -80,8 +82,6 @@
import java.util.Optional;
import java.util.Set;
-import dagger.Lazy;
-
/**
* Handles tasks and state related to media notifications. For example, there is a 'current' media
* notification, which this class keeps track of.
@@ -161,12 +161,49 @@
Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
}
mMediaArtworkProcessor.clearCache();
- mMediaMetadata = metadata;
+ mMediaMetadata = cleanMetadata(metadata);
dispatchUpdateMediaMetaData(true /* changed */, true /* allowAnimation */);
}
};
/**
+ * If this build is not configured for lockscreen artwork, clear artwork references from the
+ * metadata to avoid excess memory usage. Otherwise, return as is.
+ * @param data Original metadata
+ * @return a copy without artwork data, or original
+ */
+ private MediaMetadata cleanMetadata(MediaMetadata data) {
+ if (SHOW_LOCKSCREEN_MEDIA_ARTWORK) {
+ return data;
+ }
+ if (data == null) {
+ return null;
+ }
+ if (DEBUG_MEDIA) {
+ String[] artKeys = new String[] {
+ MediaMetadata.METADATA_KEY_ART,
+ MediaMetadata.METADATA_KEY_ALBUM_ART,
+ MediaMetadata.METADATA_KEY_DISPLAY_ICON,
+ MediaMetadata.METADATA_KEY_ALBUM_ART_URI,
+ MediaMetadata.METADATA_KEY_ART_URI,
+ MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI
+ };
+ Log.v(TAG, "DEBUG_MEDIA: removing artwork from metadata");
+ for (String key: artKeys) {
+ Log.v(TAG, " " + key + ": " + data.containsKey(key));
+ }
+ }
+ return new MediaMetadata.Builder(data)
+ .putBitmap(MediaMetadata.METADATA_KEY_ART, null)
+ .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, null)
+ .putBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON, null)
+ .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, null)
+ .putString(MediaMetadata.METADATA_KEY_ART_URI, null)
+ .putString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, null)
+ .build();
+ }
+
+ /**
* Injected constructor. See {@link CentralSurfacesModule}.
*/
public NotificationMediaManager(
@@ -313,6 +350,7 @@
return mMediaNotificationKey;
}
+ @VisibleForTesting
public MediaMetadata getMediaMetadata() {
return mMediaMetadata;
}
@@ -350,7 +388,7 @@
* update this manager's internal state.
* @return whether the current MediaMetadata changed (and needs to be announced to listeners).
*/
- boolean findPlayingMediaNotification(
+ private boolean findPlayingMediaNotification(
@NonNull Collection<NotificationEntry> allNotifications) {
boolean metaDataChanged = false;
// Promote the media notification with a controller in 'playing' state, if any.
@@ -383,7 +421,7 @@
clearCurrentMediaNotificationSession();
mMediaController = controller;
mMediaController.registerCallback(mMediaListener);
- mMediaMetadata = mMediaController.getMetadata();
+ mMediaMetadata = cleanMetadata(mMediaController.getMetadata());
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: insert listener, found new controller: "
+ mMediaController + ", receive metadata: " + mMediaMetadata);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index f579d30..b15d241 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -75,7 +75,7 @@
boolean DEBUG_WAKEUP_DELAY = Compile.IS_DEBUG;
// additional instrumentation for testing purposes; intended to be left on during development
boolean CHATTY = DEBUG;
- boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true;
+ boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = false;
String ACTION_FAKE_ARTWORK = "fake_artwork";
int FADE_KEYGUARD_START_DELAY = 100;
int FADE_KEYGUARD_DURATION = 300;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index fab334c..b3953a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -232,6 +232,7 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule;
+import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -1632,7 +1633,9 @@
}
}
mCentralSurfacesComponent = mCentralSurfacesComponentFactory.create();
- mFragmentService.addFragmentInstantiationProvider(mCentralSurfacesComponent);
+ mFragmentService.addFragmentInstantiationProvider(
+ CollapsedStatusBarFragment.class,
+ mCentralSurfacesComponent::createCollapsedStatusBarFragment);
mNotificationShadeWindowView = mCentralSurfacesComponent.getNotificationShadeWindowView();
mNotificationShadeWindowViewController = mCentralSurfacesComponent
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index a9920ec7..8f4b320 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -101,7 +101,8 @@
whenever(smallClockController.events).thenReturn(smallClockEvents)
whenever(largeClockController.events).thenReturn(largeClockEvents)
whenever(clock.events).thenReturn(events)
- whenever(clock.animations).thenReturn(animations)
+ whenever(smallClockController.animations).thenReturn(animations)
+ whenever(largeClockController.animations).thenReturn(animations)
whenever(smallClockController.config)
.thenReturn(ClockFaceConfig(tickRate = ClockTickRate.PER_MINUTE))
whenever(largeClockController.config)
@@ -184,7 +185,7 @@
keyguardCaptor.value.onKeyguardVisibilityChanged(true)
batteryCaptor.value.onBatteryLevelChanged(10, false, true)
- verify(animations).charge()
+ verify(animations, times(2)).charge()
}
@Test
@@ -198,7 +199,7 @@
batteryCaptor.value.onBatteryLevelChanged(10, false, true)
batteryCaptor.value.onBatteryLevelChanged(10, false, true)
- verify(animations, times(1)).charge()
+ verify(animations, times(2)).charge()
}
@Test
@@ -246,7 +247,7 @@
verify(animations, never()).doze(0f)
captor.value.onKeyguardVisibilityChanged(false)
- verify(animations, times(1)).doze(0f)
+ verify(animations, times(2)).doze(0f)
}
@Test
@@ -284,7 +285,7 @@
yield()
- verify(animations).doze(0.4f)
+ verify(animations, times(2)).doze(0.4f)
job.cancel()
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index fc906de..95db0c0 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -184,13 +184,14 @@
when(mClockController.getEvents()).thenReturn(mClockEvents);
when(mSmallClockController.getEvents()).thenReturn(mClockFaceEvents);
when(mLargeClockController.getEvents()).thenReturn(mClockFaceEvents);
- when(mClockController.getAnimations()).thenReturn(mClockAnimations);
+ when(mLargeClockController.getAnimations()).thenReturn(mClockAnimations);
+ when(mSmallClockController.getAnimations()).thenReturn(mClockAnimations);
when(mClockRegistry.createCurrentClock()).thenReturn(mClockController);
when(mClockEventController.getClock()).thenReturn(mClockController);
when(mSmallClockController.getConfig())
- .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false));
+ .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false));
when(mLargeClockController.getConfig())
- .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false));
+ .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false));
mSliceView = new View(getContext());
when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView);
@@ -384,9 +385,9 @@
assertEquals(View.VISIBLE, mFakeDateView.getVisibility());
when(mSmallClockController.getConfig())
- .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, true));
+ .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, true, false));
when(mLargeClockController.getConfig())
- .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, true));
+ .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, true, false));
verify(mClockRegistry).registerClockChangeListener(listenerArgumentCaptor.capture());
listenerArgumentCaptor.getValue().onCurrentClockChanged();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 2c1d2ad..a2c6329 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -130,7 +130,7 @@
public void updatePosition_primaryClockAnimation() {
ClockController mockClock = mock(ClockController.class);
when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock);
- when(mockClock.getConfig()).thenReturn(new ClockConfig(false, false, true));
+ when(mockClock.getConfig()).thenReturn(new ClockConfig(false, true));
mController.updatePosition(10, 15, 20f, true);
@@ -145,7 +145,7 @@
public void updatePosition_alternateClockAnimation() {
ClockController mockClock = mock(ClockController.class);
when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock);
- when(mockClock.getConfig()).thenReturn(new ClockConfig(false, true, true));
+ when(mockClock.getConfig()).thenReturn(new ClockConfig(true, true));
mController.updatePosition(10, 15, 20f, true);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 3eb9590..ed40eed 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -155,6 +155,7 @@
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
import org.mockito.internal.util.reflection.FieldSetter;
+import org.mockito.quality.Strictness;
import java.util.ArrayList;
import java.util.Arrays;
@@ -303,6 +304,7 @@
mMockitoSession = ExtendedMockito.mockitoSession()
.spyStatic(SubscriptionManager.class)
+ .strictness(Strictness.WARN)
.startMocking();
ExtendedMockito.doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
.when(SubscriptionManager::getDefaultSubscriptionId);
@@ -2528,19 +2530,6 @@
}
@Test
- public void testBatteryChangedIntent_unplugDevice_resetIncompatibleCharger() {
- mKeyguardUpdateMonitor.mIncompatibleCharger = true;
- Intent batteryChangedIntent =
- getBatteryIntent().putExtra(BatteryManager.EXTRA_PLUGGED, -1);
-
- mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(mContext, batteryChangedIntent);
-
- BatteryStatus status = verifyRefreshBatteryInfo();
- assertThat(status.incompatibleCharger.get()).isFalse();
- assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isFalse();
- }
-
- @Test
public void unfoldWakeup_requestActiveUnlock_forceDismissKeyguard()
throws RemoteException {
// GIVEN shouldTriggerActiveUnlock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt
index 80c3e5e..937a7a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt
@@ -172,64 +172,64 @@
}
@Test
- fun `canCameraGestureBeLaunched - status bar state is keyguard - returns true`() {
+ fun canCameraGestureBeLaunched_statusBarStateIsKeyguard_returnsTrue() {
assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.KEYGUARD)).isTrue()
}
@Test
- fun `canCameraGestureBeLaunched - state is shade-locked - returns true`() {
+ fun canCameraGestureBeLaunched_stateIsShadeLocked_returnsTrue() {
assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.SHADE_LOCKED)).isTrue()
}
@Test
- fun `canCameraGestureBeLaunched - state is keyguard - camera activity on top - returns true`() {
+ fun canCameraGestureBeLaunched_stateIsKeyguard_cameraActivityOnTop_returnsTrue() {
prepare(isCameraActivityRunningOnTop = true)
assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.KEYGUARD)).isTrue()
}
@Test
- fun `canCameraGestureBeLaunched - state is shade-locked - camera activity on top - true`() {
+ fun canCameraGestureBeLaunched_stateIsShadeLocked_cameraActivityOnTop_true() {
prepare(isCameraActivityRunningOnTop = true)
assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.SHADE_LOCKED)).isTrue()
}
@Test
- fun `canCameraGestureBeLaunched - not allowed by admin - returns false`() {
+ fun canCameraGestureBeLaunched_notAllowedByAdmin_returnsFalse() {
prepare(isCameraAllowedByAdmin = false)
assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.KEYGUARD)).isFalse()
}
@Test
- fun `canCameraGestureBeLaunched - intent does not resolve to any app - returns false`() {
+ fun canCameraGestureBeLaunched_intentDoesNotResolveToAnyApp_returnsFalse() {
prepare(installedCameraAppCount = 0)
assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.KEYGUARD)).isFalse()
}
@Test
- fun `canCameraGestureBeLaunched - state is shade - no running tasks - returns true`() {
+ fun canCameraGestureBeLaunched_stateIsShade_noRunningTasks_returnsTrue() {
prepare(isCameraActivityRunningOnTop = false, isTaskListEmpty = true)
assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.SHADE)).isTrue()
}
@Test
- fun `canCameraGestureBeLaunched - state is shade - camera activity on top - returns false`() {
+ fun canCameraGestureBeLaunched_stateIsShade_cameraActivityOnTop_returnsFalse() {
prepare(isCameraActivityRunningOnTop = true)
assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.SHADE)).isFalse()
}
@Test
- fun `canCameraGestureBeLaunched - state is shade - camera activity not on top - true`() {
+ fun canCameraGestureBeLaunched_stateIsShade_cameraActivityNotOnTop_true() {
assertThat(underTest.canCameraGestureBeLaunched(StatusBarState.SHADE)).isTrue()
}
@Test
- fun `launchCamera - only one camera app installed - using secure screen lock option`() {
+ fun launchCamera_onlyOneCameraAppInstalled_usingSecureScreenLockOption() {
val source = 1337
underTest.launchCamera(source)
@@ -238,7 +238,7 @@
}
@Test
- fun `launchCamera - only one camera app installed - using non-secure screen lock option`() {
+ fun launchCamera_onlyOneCameraAppInstalled_usingNonSecureScreenLockOption() {
prepare(isUsingSecureScreenLockOption = false)
val source = 1337
@@ -248,7 +248,7 @@
}
@Test
- fun `launchCamera - multiple camera apps installed - using secure screen lock option`() {
+ fun launchCamera_multipleCameraAppsInstalled_usingSecureScreenLockOption() {
prepare(installedCameraAppCount = 2)
val source = 1337
@@ -262,7 +262,7 @@
}
@Test
- fun `launchCamera - multiple camera apps installed - using non-secure screen lock option`() {
+ fun launchCamera_multipleCameraAppsInstalled_usingNonSecureScreenLockOption() {
prepare(
isUsingSecureScreenLockOption = false,
installedCameraAppCount = 2,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
index 8600b7c..fe5fa1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
@@ -25,7 +25,6 @@
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHOWN_EXPANDED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHOWN_MINIMIZED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
-import static com.android.systemui.flags.Flags.CLIPBOARD_REMOTE_BEHAVIOR;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -121,7 +120,6 @@
mSampleClipData = new ClipData("Test", new String[]{"text/plain"},
new ClipData.Item("Test Item"));
- mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, false);
mOverlayController = new ClipboardOverlayController(
mContext,
@@ -234,7 +232,6 @@
@Test
public void test_remoteCopy_withFlagOn() {
- mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true);
when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(true);
mOverlayController.setClipData(mSampleClipData, "");
@@ -243,17 +240,7 @@
}
@Test
- public void test_remoteCopy_withFlagOff() {
- when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(true);
-
- mOverlayController.setClipData(mSampleClipData, "");
-
- verify(mTimeoutHandler).resetTimeout();
- }
-
- @Test
public void test_nonRemoteCopy() {
- mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true);
when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(false);
mOverlayController.setClipData(mSampleClipData, "");
@@ -279,7 +266,6 @@
public void test_logOnClipboardActionsShown() {
ClipData.Item item = mSampleClipData.getItemAt(0);
item.setTextLinks(Mockito.mock(TextLinks.class));
- mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true);
when(mClipboardUtils.isRemoteCopy(any(Context.class), any(ClipData.class), anyString()))
.thenReturn(true);
when(mClipboardUtils.getAction(any(TextLinks.class), anyString()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt
index fe352fd..1b2fc93d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt
@@ -72,7 +72,7 @@
}
@Test
- fun `long-press`() = runTest {
+ fun longPress() = runTest {
val downX = 123
val downY = 456
dispatchTouchEvents(
@@ -91,7 +91,7 @@
}
@Test
- fun `long-press but feature not enabled`() = runTest {
+ fun longPressButFeatureNotEnabled() = runTest {
underTest.isLongPressHandlingEnabled = false
dispatchTouchEvents(
Down(
@@ -106,7 +106,7 @@
}
@Test
- fun `long-press but view not attached`() = runTest {
+ fun longPressButViewNotAttached() = runTest {
isAttachedToWindow = false
dispatchTouchEvents(
Down(
@@ -121,7 +121,7 @@
}
@Test
- fun `dragged too far to be considered a long-press`() = runTest {
+ fun draggedTooFarToBeConsideredAlongPress() = runTest {
dispatchTouchEvents(
Down(
x = 123,
@@ -138,7 +138,7 @@
}
@Test
- fun `held down too briefly to be considered a long-press`() = runTest {
+ fun heldDownTooBrieflyToBeConsideredAlongPress() = runTest {
dispatchTouchEvents(
Down(
x = 123,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
index 87c66b5..75eec72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
@@ -74,7 +74,7 @@
}
@Test
- fun `demo command flow - returns args`() =
+ fun demoCommandFlow_returnsArgs() =
testScope.runTest {
var latest: Bundle? = null
val flow = underTest.demoFlowForCommand(TEST_COMMAND)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt
index a2dc1eb..4ba1bc6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt
@@ -5,7 +5,6 @@
import android.test.suitebuilder.annotation.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
-import com.android.systemui.qs.QSFragment
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -13,9 +12,7 @@
@SmallTest
class FragmentServiceTest : SysuiTestCase() {
- private val fragmentCreator = TestFragmentCreator()
- private val fragmenetHostManagerFactory: FragmentHostManager.Factory = mock()
- private val fragmentCreatorFactory = FragmentService.FragmentCreator.Factory { fragmentCreator }
+ private val fragmentHostManagerFactory: FragmentHostManager.Factory = mock()
private lateinit var fragmentService: FragmentService
@@ -25,65 +22,29 @@
Looper.prepare()
}
- fragmentService =
- FragmentService(
- fragmentCreatorFactory,
- fragmenetHostManagerFactory,
- mock(),
- DumpManager()
- )
- }
-
- @Test
- fun constructor_addsFragmentCreatorMethodsToMap() {
- val map = fragmentService.injectionMap
- assertThat(map).hasSize(2)
- assertThat(map.keys).contains(QSFragment::class.java.name)
- assertThat(map.keys).contains(TestFragmentInCreator::class.java.name)
+ fragmentService = FragmentService(fragmentHostManagerFactory, mock(), DumpManager())
}
@Test
fun addFragmentInstantiationProvider_objectHasNoFragmentMethods_nothingAdded() {
- fragmentService.addFragmentInstantiationProvider(Object())
+ fragmentService.addFragmentInstantiationProvider(TestFragment::class.java) {
+ TestFragment()
+ }
- assertThat(fragmentService.injectionMap).hasSize(2)
- }
-
- @Test
- fun addFragmentInstantiationProvider_objectHasFragmentMethods_methodsAdded() {
- fragmentService.addFragmentInstantiationProvider(
- @Suppress("unused")
- object : Any() {
- fun createTestFragment2() = TestFragment2()
- fun createTestFragment3() = TestFragment3()
- }
- )
-
- val map = fragmentService.injectionMap
- assertThat(map).hasSize(4)
- assertThat(map.keys).contains(TestFragment2::class.java.name)
- assertThat(map.keys).contains(TestFragment3::class.java.name)
+ assertThat(fragmentService.injectionMap).hasSize(1)
}
@Test
fun addFragmentInstantiationProvider_objectFragmentMethodsAlreadyProvided_nothingAdded() {
- fragmentService.addFragmentInstantiationProvider(
- @Suppress("unused")
- object : Any() {
- fun createTestFragment() = TestFragmentInCreator()
- }
- )
+ fragmentService.addFragmentInstantiationProvider(TestFragment::class.java) {
+ TestFragment()
+ }
+ fragmentService.addFragmentInstantiationProvider(TestFragment::class.java) {
+ TestFragment()
+ }
- assertThat(fragmentService.injectionMap).hasSize(2)
+ assertThat(fragmentService.injectionMap).hasSize(1)
}
- class TestFragmentCreator : FragmentService.FragmentCreator {
- override fun createQSFragment(): QSFragment = mock()
- @Suppress("unused")
- fun createTestFragment(): TestFragmentInCreator = TestFragmentInCreator()
- }
-
- class TestFragmentInCreator : Fragment()
- class TestFragment2 : Fragment()
- class TestFragment3 : Fragment()
+ class TestFragment : Fragment()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index 1044131..4daecd9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -211,7 +211,7 @@
}
@Test
- fun `onAttachInfo - reportsContext`() {
+ fun onAttachInfo_reportsContext() {
val callback: SystemUIAppComponentFactoryBase.ContextAvailableCallback = mock()
underTest.setContextAvailableCallback(callback)
@@ -254,7 +254,7 @@
}
@Test
- fun `insert and query selection`() =
+ fun insertAndQuerySelection() =
testScope.runTest {
val slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START
val affordanceId = AFFORDANCE_2
@@ -278,7 +278,7 @@
}
@Test
- fun `query slots`() =
+ fun querySlotsProvidesTwoSlots() =
testScope.runTest {
assertThat(querySlots())
.isEqualTo(
@@ -296,7 +296,7 @@
}
@Test
- fun `query affordances`() =
+ fun queryAffordancesProvidesTwoAffordances() =
testScope.runTest {
assertThat(queryAffordances())
.isEqualTo(
@@ -316,7 +316,7 @@
}
@Test
- fun `delete and query selection`() =
+ fun deleteAndQuerySelection() =
testScope.runTest {
insertSelection(
slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
@@ -351,7 +351,7 @@
}
@Test
- fun `delete all selections in a slot`() =
+ fun deleteAllSelectionsInAslot() =
testScope.runTest {
insertSelection(
slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
index 5bb8367..e20d3af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
@@ -73,7 +73,7 @@
}
@Test
- fun `affordance triggered -- camera launch called`() {
+ fun affordanceTriggered_cameraLaunchCalled() {
// When
val result = underTest.onTriggered(null)
@@ -84,7 +84,7 @@
}
@Test
- fun `getPickerScreenState - default when launchable`() =
+ fun getPickerScreenState_defaultWhenLaunchable() =
testScope.runTest {
setLaunchable(true)
@@ -93,7 +93,7 @@
}
@Test
- fun `getPickerScreenState - unavailable when camera app not installed`() =
+ fun getPickerScreenState_unavailableWhenCameraAppNotInstalled() =
testScope.runTest {
setLaunchable(isCameraAppInstalled = false)
@@ -102,7 +102,7 @@
}
@Test
- fun `getPickerScreenState - unavailable when camera disabled by admin`() =
+ fun getPickerScreenState_unavailableWhenCameraDisabledByAdmin() =
testScope.runTest {
setLaunchable(isCameraDisabledByDeviceAdmin = true)
@@ -111,7 +111,7 @@
}
@Test
- fun `getPickerScreenState - unavailable when secure camera disabled by admin`() =
+ fun getPickerScreenState_unavailableWhenSecureCameraDisabledByAdmin() =
testScope.runTest {
setLaunchable(isSecureCameraDisabledByDeviceAdmin = true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt
index 64839e2..c326a86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt
@@ -97,7 +97,7 @@
}
@Test
- fun `dnd not available - picker state hidden`() =
+ fun dndNotAvailable_pickerStateHidden() =
testScope.runTest {
// given
whenever(zenModeController.isZenAvailable).thenReturn(false)
@@ -113,7 +113,7 @@
}
@Test
- fun `dnd available - picker state visible`() =
+ fun dndAvailable_pickerStateVisible() =
testScope.runTest {
// given
whenever(zenModeController.isZenAvailable).thenReturn(true)
@@ -132,7 +132,7 @@
}
@Test
- fun `onTriggered - dnd mode is not ZEN_MODE_OFF - set to ZEN_MODE_OFF`() =
+ fun onTriggered_dndModeIsNotZEN_MODE_OFF_setToZEN_MODE_OFF() =
testScope.runTest {
// given
whenever(zenModeController.isZenAvailable).thenReturn(true)
@@ -157,7 +157,7 @@
}
@Test
- fun `onTriggered - dnd mode is ZEN_MODE_OFF - setting FOREVER - set zen without condition`() =
+ fun onTriggered_dndModeIsZEN_MODE_OFF_settingFOREVER_setZenWithoutCondition() =
testScope.runTest {
// given
whenever(zenModeController.isZenAvailable).thenReturn(true)
@@ -182,7 +182,7 @@
}
@Test
- fun `onTriggered - dnd ZEN_MODE_OFF - setting not FOREVER or PROMPT - zen with condition`() =
+ fun onTriggered_dndZEN_MODE_OFF_settingNotFOREVERorPROMPT_zenWithCondition() =
testScope.runTest {
// given
whenever(zenModeController.isZenAvailable).thenReturn(true)
@@ -207,7 +207,7 @@
}
@Test
- fun `onTriggered - dnd mode is ZEN_MODE_OFF - setting is PROMPT - show dialog`() =
+ fun onTriggered_dndModeIsZEN_MODE_OFF_settingIsPROMPT_showDialog() =
testScope.runTest {
// given
val expandable: Expandable = mock()
@@ -230,7 +230,7 @@
}
@Test
- fun `lockScreenState - dndAvailable starts as true - change to false - State is Hidden`() =
+ fun lockScreenState_dndAvailableStartsAsTrue_changeToFalse_StateIsHidden() =
testScope.runTest {
// given
whenever(zenModeController.isZenAvailable).thenReturn(true)
@@ -249,7 +249,7 @@
}
@Test
- fun `lockScreenState - dndMode starts as ZEN_MODE_OFF - change to not OFF - State Visible`() =
+ fun lockScreenState_dndModeStartsAsZEN_MODE_OFF_changeToNotOFF_StateVisible() =
testScope.runTest {
// given
whenever(zenModeController.isZenAvailable).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt
index 31391ee..292d067 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt
@@ -60,7 +60,7 @@
}
@Test
- fun `flashlight is off -- triggered -- icon is on and active`() = runTest {
+ fun flashlightIsOff_triggered_iconIsOnAndActive() = runTest {
// given
flashlightController.isEnabled = false
flashlightController.isAvailable = true
@@ -83,7 +83,7 @@
}
@Test
- fun `flashlight is on -- triggered -- icon is off and inactive`() = runTest {
+ fun flashlightIsOn_triggered_iconIsOffAndInactive() = runTest {
// given
flashlightController.isEnabled = true
flashlightController.isAvailable = true
@@ -106,7 +106,7 @@
}
@Test
- fun `flashlight is on -- receives error -- icon is off and inactive`() = runTest {
+ fun flashlightIsOn_receivesError_iconIsOffAndInactive() = runTest {
// given
flashlightController.isEnabled = true
flashlightController.isAvailable = false
@@ -129,7 +129,7 @@
}
@Test
- fun `flashlight availability now off -- hidden`() = runTest {
+ fun flashlightAvailabilityNowOff_hidden() = runTest {
// given
flashlightController.isEnabled = true
flashlightController.isAvailable = false
@@ -146,7 +146,7 @@
}
@Test
- fun `flashlight availability now on -- flashlight on -- inactive and icon off`() = runTest {
+ fun flashlightAvailabilityNowOn_flashlightOn_inactiveAndIconOff() = runTest {
// given
flashlightController.isEnabled = true
flashlightController.isAvailable = false
@@ -168,7 +168,7 @@
}
@Test
- fun `flashlight availability now on -- flashlight off -- inactive and icon off`() = runTest {
+ fun flashlightAvailabilityNowOn_flashlightOff_inactiveAndIconOff() = runTest {
// given
flashlightController.isEnabled = false
flashlightController.isAvailable = false
@@ -190,7 +190,7 @@
}
@Test
- fun `flashlight available -- picker state default`() = runTest {
+ fun flashlightAvailable_pickerStateDefault() = runTest {
// given
flashlightController.isAvailable = true
@@ -202,7 +202,7 @@
}
@Test
- fun `flashlight not available -- picker state unavailable`() = runTest {
+ fun flashlightNotAvailable_pickerStateUnavailable() = runTest {
// given
flashlightController.isAvailable = false
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
index 2c1c04c..26f0cdb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
@@ -61,7 +61,7 @@
}
@Test
- fun `state - when cannot show while locked - returns Hidden`() = runBlockingTest {
+ fun state_whenCannotShowWhileLocked_returnsHidden() = runBlockingTest {
whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false))
whenever(component.isEnabled()).thenReturn(true)
whenever(component.getTileImageId()).thenReturn(R.drawable.controls_icon)
@@ -81,7 +81,7 @@
}
@Test
- fun `state - when listing controller is missing - returns Hidden`() = runBlockingTest {
+ fun state_whenListingControllerIsMissing_returnsHidden() = runBlockingTest {
whenever(component.isEnabled()).thenReturn(true)
whenever(component.getTileImageId()).thenReturn(R.drawable.controls_icon)
whenever(component.getTileTitleId()).thenReturn(R.string.quick_controls_title)
@@ -100,7 +100,7 @@
}
@Test
- fun `onQuickAffordanceTriggered - canShowWhileLockedSetting is true`() = runBlockingTest {
+ fun onQuickAffordanceTriggered_canShowWhileLockedSettingIsTrue() = runBlockingTest {
whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(true))
val onClickedResult = underTest.onTriggered(expandable)
@@ -110,7 +110,7 @@
}
@Test
- fun `onQuickAffordanceTriggered - canShowWhileLockedSetting is false`() = runBlockingTest {
+ fun onQuickAffordanceTriggered_canShowWhileLockedSettingIsFalse() = runBlockingTest {
whenever(component.canShowWhileLockedSetting).thenReturn(MutableStateFlow(false))
val onClickedResult = underTest.onTriggered(expandable)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt
index 3bae7f7..9a18ba8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt
@@ -106,7 +106,7 @@
}
@Test
- fun `Setting a setting selects the affordance`() =
+ fun settingAsettingSelectsTheAffordance() =
testScope.runTest {
val job = underTest.startSyncing()
@@ -129,7 +129,7 @@
}
@Test
- fun `Clearing a setting selects the affordance`() =
+ fun clearingAsettingSelectsTheAffordance() =
testScope.runTest {
val job = underTest.startSyncing()
@@ -156,7 +156,7 @@
}
@Test
- fun `Selecting an affordance sets its setting`() =
+ fun selectingAnAffordanceSetsItsSetting() =
testScope.runTest {
val job = underTest.startSyncing()
@@ -172,7 +172,7 @@
}
@Test
- fun `Unselecting an affordance clears its setting`() =
+ fun unselectingAnAffordanceClearsItsSetting() =
testScope.runTest {
val job = underTest.startSyncing()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt
index 1259b47..6989f44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt
@@ -164,7 +164,7 @@
}
@Test
- fun `remembers selections by user`() = runTest {
+ fun remembersSelectionsByUser() = runTest {
overrideResource(
R.array.config_keyguardQuickAffordanceDefaults,
arrayOf<String>(),
@@ -246,7 +246,7 @@
}
@Test
- fun `selections respects defaults`() = runTest {
+ fun selectionsRespectsDefaults() = runTest {
val slotId1 = "slot1"
val slotId2 = "slot2"
val affordanceId1 = "affordance1"
@@ -277,7 +277,7 @@
}
@Test
- fun `selections ignores defaults after selecting an affordance`() = runTest {
+ fun selectionsIgnoresDefaultsAfterSelectingAnAffordance() = runTest {
val slotId1 = "slot1"
val slotId2 = "slot2"
val affordanceId1 = "affordance1"
@@ -309,7 +309,7 @@
}
@Test
- fun `selections ignores defaults after clearing a slot`() = runTest {
+ fun selectionsIgnoresDefaultsAfterClearingAslot() = runTest {
val slotId1 = "slot1"
val slotId2 = "slot2"
val affordanceId1 = "affordance1"
@@ -341,7 +341,7 @@
}
@Test
- fun `responds to backup and restore by reloading the selections from disk`() = runTest {
+ fun respondsToBackupAndRestoreByReloadingTheSelectionsFromDisk() = runTest {
overrideResource(R.array.config_keyguardQuickAffordanceDefaults, arrayOf<String>())
val affordanceIdsBySlotId = mutableListOf<Map<String, List<String>>>()
val job =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt
index c08ef42..a1c9f87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt
@@ -112,7 +112,7 @@
}
@Test
- fun `selections - primary user process`() =
+ fun selections_primaryUserProcess() =
testScope.runTest {
val values = mutableListOf<Map<String, List<String>>>()
val job = launch { underTest.selections.toList(values) }
@@ -163,7 +163,7 @@
}
@Test
- fun `selections - secondary user process - always empty`() =
+ fun selections_secondaryUserProcess_alwaysEmpty() =
testScope.runTest {
whenever(userHandle.isSystem).thenReturn(false)
val values = mutableListOf<Map<String, List<String>>>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt
index 925c06f..c38827a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt
@@ -85,7 +85,7 @@
}
@Test
- fun `picker state - volume fixed - not available`() = testScope.runTest {
+ fun pickerState_volumeFixed_notAvailable() = testScope.runTest {
//given
whenever(audioManager.isVolumeFixed).thenReturn(true)
@@ -97,7 +97,7 @@
}
@Test
- fun `picker state - volume not fixed - available`() = testScope.runTest {
+ fun pickerState_volumeNotFixed_available() = testScope.runTest {
//given
whenever(audioManager.isVolumeFixed).thenReturn(false)
@@ -109,7 +109,7 @@
}
@Test
- fun `triggered - state was previously NORMAL - currently SILENT - move to previous state`() = testScope.runTest {
+ fun triggered_stateWasPreviouslyNORMAL_currentlySILENT_moveToPreviousState() = testScope.runTest {
//given
val ringerModeCapture = argumentCaptor<Int>()
whenever(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_NORMAL)
@@ -127,7 +127,7 @@
}
@Test
- fun `triggered - state is not SILENT - move to SILENT ringer`() = testScope.runTest {
+ fun triggered_stateIsNotSILENT_moveToSILENTringer() = testScope.runTest {
//given
val ringerModeCapture = argumentCaptor<Int>()
whenever(audioManager.ringerModeInternal).thenReturn(AudioManager.RINGER_MODE_NORMAL)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt
index facc747..f243d7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt
@@ -101,7 +101,7 @@
}
@Test
- fun `feature flag is OFF - do nothing with keyguardQuickAffordanceRepository`() = testScope.runTest {
+ fun featureFlagIsOFF_doNothingWithKeyguardQuickAffordanceRepository() = testScope.runTest {
//given
whenever(featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES)).thenReturn(false)
@@ -114,7 +114,7 @@
}
@Test
- fun `feature flag is ON - call to keyguardQuickAffordanceRepository`() = testScope.runTest {
+ fun featureFlagIsON_callToKeyguardQuickAffordanceRepository() = testScope.runTest {
//given
val ringerModeInternal = mock<MutableLiveData<Int>>()
whenever(ringerModeTracker.ringerModeInternal).thenReturn(ringerModeInternal)
@@ -129,7 +129,7 @@
}
@Test
- fun `ringer mode is changed to SILENT - do not save to shared preferences`() = testScope.runTest {
+ fun ringerModeIsChangedToSILENT_doNotSaveToSharedPreferences() = testScope.runTest {
//given
val ringerModeInternal = mock<MutableLiveData<Int>>()
val observerCaptor = argumentCaptor<Observer<Int>>()
@@ -147,7 +147,7 @@
}
@Test
- fun `ringerModeInternal changes to something not SILENT - is set in sharedpreferences`() = testScope.runTest {
+ fun ringerModeInternalChangesToSomethingNotSILENT_isSetInSharedpreferences() = testScope.runTest {
//given
val newRingerMode = 99
val observerCaptor = argumentCaptor<Observer<Int>>()
@@ -172,7 +172,7 @@
}
@Test
- fun `MUTE is in selections - observe ringerModeInternal`() = testScope.runTest {
+ fun MUTEisInSelections_observeRingerModeInternal() = testScope.runTest {
//given
val ringerModeInternal = mock<MutableLiveData<Int>>()
whenever(ringerModeTracker.ringerModeInternal).thenReturn(ringerModeInternal)
@@ -187,7 +187,7 @@
}
@Test
- fun `MUTE is in selections 2x - observe ringerModeInternal`() = testScope.runTest {
+ fun MUTEisInSelections2x_observeRingerModeInternal() = testScope.runTest {
//given
val config: KeyguardQuickAffordanceConfig = mock()
whenever(config.key).thenReturn(BuiltInKeyguardQuickAffordanceKeys.MUTE)
@@ -206,7 +206,7 @@
}
@Test
- fun `MUTE is not in selections - stop observing ringerModeInternal`() = testScope.runTest {
+ fun MUTEisNotInSelections_stopObservingRingerModeInternal() = testScope.runTest {
//given
val config: KeyguardQuickAffordanceConfig = mock()
whenever(config.key).thenReturn("notmutequickaffordance")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
index 1adf808..faf18d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
@@ -55,7 +55,7 @@
}
@Test
- fun `affordance - sets up registration and delivers initial model`() = runBlockingTest {
+ fun affordance_setsUpRegistrationAndDeliversInitialModel() = runBlockingTest {
whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
@@ -75,7 +75,7 @@
}
@Test
- fun `affordance - scanner activity changed - delivers model with updated intent`() =
+ fun affordance_scannerActivityChanged_deliversModelWithUpdatedIntent() =
runBlockingTest {
whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
@@ -93,7 +93,7 @@
}
@Test
- fun `affordance - scanner preference changed - delivers visible model`() = runBlockingTest {
+ fun affordance_scannerPreferenceChanged_deliversVisibleModel() = runBlockingTest {
var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
@@ -109,7 +109,7 @@
}
@Test
- fun `affordance - scanner preference changed - delivers none`() = runBlockingTest {
+ fun affordance_scannerPreferenceChanged_deliversNone() = runBlockingTest {
var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
@@ -136,7 +136,7 @@
}
@Test
- fun `getPickerScreenState - enabled if configured on device - can open camera`() = runTest {
+ fun getPickerScreenState_enabledIfConfiguredOnDevice_canOpenCamera() = runTest {
whenever(controller.isAvailableOnDevice).thenReturn(true)
whenever(controller.isAbleToOpenCameraApp).thenReturn(true)
@@ -145,7 +145,7 @@
}
@Test
- fun `getPickerScreenState - disabled if configured on device - cannot open camera`() = runTest {
+ fun getPickerScreenState_disabledIfConfiguredOnDevice_cannotOpenCamera() = runTest {
whenever(controller.isAvailableOnDevice).thenReturn(true)
whenever(controller.isAbleToOpenCameraApp).thenReturn(false)
@@ -154,7 +154,7 @@
}
@Test
- fun `getPickerScreenState - unavailable if not configured on device`() = runTest {
+ fun getPickerScreenState_unavailableIfNotConfiguredOnDevice() = runTest {
whenever(controller.isAvailableOnDevice).thenReturn(false)
whenever(controller.isAbleToOpenCameraApp).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
index 752963f..952882d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
@@ -69,7 +69,7 @@
}
@Test
- fun `affordance - keyguard showing - has wallet card - visible model`() = runBlockingTest {
+ fun affordance_keyguardShowing_hasWalletCard_visibleModel() = runBlockingTest {
setUpState()
var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
@@ -90,7 +90,7 @@
}
@Test
- fun `affordance - wallet not enabled - model is none`() = runBlockingTest {
+ fun affordance_walletNotEnabled_modelIsNone() = runBlockingTest {
setUpState(isWalletEnabled = false)
var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
@@ -102,7 +102,7 @@
}
@Test
- fun `affordance - query not successful - model is none`() = runBlockingTest {
+ fun affordance_queryNotSuccessful_modelIsNone() = runBlockingTest {
setUpState(isWalletQuerySuccessful = false)
var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
@@ -114,7 +114,7 @@
}
@Test
- fun `affordance - no selected card - model is none`() = runBlockingTest {
+ fun affordance_noSelectedCard_modelIsNone() = runBlockingTest {
setUpState(hasSelectedCard = false)
var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
@@ -143,7 +143,7 @@
}
@Test
- fun `getPickerScreenState - default`() = runTest {
+ fun getPickerScreenState_default() = runTest {
setUpState()
assertThat(underTest.getPickerScreenState())
@@ -151,7 +151,7 @@
}
@Test
- fun `getPickerScreenState - unavailable`() = runTest {
+ fun getPickerScreenState_unavailable() = runTest {
setUpState(
isWalletServiceAvailable = false,
)
@@ -161,7 +161,7 @@
}
@Test
- fun `getPickerScreenState - disabled when the feature is not enabled`() = runTest {
+ fun getPickerScreenState_disabledWhenTheFeatureIsNotEnabled() = runTest {
setUpState(
isWalletEnabled = false,
)
@@ -171,7 +171,7 @@
}
@Test
- fun `getPickerScreenState - disabled when there is no card`() = runTest {
+ fun getPickerScreenState_disabledWhenThereIsNoCard() = runTest {
setUpState(
hasSelectedCard = false,
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
index f1b9c5f..a9b9c90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt
@@ -73,7 +73,7 @@
}
@Test
- fun `lockScreenState - visible when launchable`() =
+ fun lockScreenState_visibleWhenLaunchable() =
testScope.runTest {
setLaunchable()
@@ -84,7 +84,7 @@
}
@Test
- fun `lockScreenState - hidden when app not installed on device`() =
+ fun lockScreenState_hiddenWhenAppNotInstalledOnDevice() =
testScope.runTest {
setLaunchable(isVideoCameraAppInstalled = false)
@@ -95,7 +95,7 @@
}
@Test
- fun `lockScreenState - hidden when camera disabled by admin`() =
+ fun lockScreenState_hiddenWhenCameraDisabledByAdmin() =
testScope.runTest {
setLaunchable(isCameraDisabledByAdmin = true)
@@ -106,7 +106,7 @@
}
@Test
- fun `getPickerScreenState - default when launchable`() =
+ fun getPickerScreenState_defaultWhenLaunchable() =
testScope.runTest {
setLaunchable()
@@ -115,7 +115,7 @@
}
@Test
- fun `getPickerScreenState - unavailable when app not installed on device`() =
+ fun getPickerScreenState_unavailableWhenAppNotInstalledOnDevice() =
testScope.runTest {
setLaunchable(isVideoCameraAppInstalled = false)
@@ -124,7 +124,7 @@
}
@Test
- fun `getPickerScreenState - unavailable when camera disabled by admin`() =
+ fun getPickerScreenState_unavailableWhenCameraDisabledByAdmin() =
testScope.runTest {
setLaunchable(isCameraDisabledByAdmin = true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index fc75d47..a76d03b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -21,6 +21,7 @@
import android.content.pm.UserInfo
import android.content.pm.UserInfo.FLAG_PRIMARY
import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_CANCELED
+import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE
import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT
import android.hardware.biometrics.ComponentInfoInternal
import android.hardware.face.FaceAuthenticateOptions
@@ -824,6 +825,26 @@
verify(faceManager).scheduleWatchdog()
}
+ @Test
+ fun retryFaceIfThereIsAHardwareError() =
+ testScope.runTest {
+ initCollectors()
+ allPreconditionsToRunFaceAuthAreTrue()
+
+ triggerFaceAuth(fallbackToDetect = false)
+ clearInvocations(faceManager)
+
+ authenticationCallback.value.onAuthenticationError(
+ FACE_ERROR_HW_UNAVAILABLE,
+ "HW unavailable"
+ )
+
+ advanceTimeBy(DeviceEntryFaceAuthRepositoryImpl.HAL_ERROR_RETRY_TIMEOUT)
+ runCurrent()
+
+ faceAuthenticateIsCalled()
+ }
+
private suspend fun TestScope.testGatingCheckForFaceAuth(gatingCheckModifier: () -> Unit) {
initCollectors()
allPreconditionsToRunFaceAuthAreTrue()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt
index a668af3..12b8261 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt
@@ -258,7 +258,7 @@
}
@Test
- fun `selections for secondary user`() =
+ fun selectionsForSecondaryUser() =
testScope.runTest {
userTracker.set(
userInfos =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 3fd97da..b53a434 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -281,7 +281,7 @@
}
@Test
- fun `isDozing - starts with correct initial value for isDozing`() =
+ fun isDozing_startsWithCorrectInitialValueForIsDozing() =
testScope.runTest {
var latest: Boolean? = null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index d9d4013..d0bfaa9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -70,7 +70,7 @@
}
@Test
- fun `startTransition runs animator to completion`() =
+ fun startTransitionRunsAnimatorToCompletion() =
TestScope().runTest {
val steps = mutableListOf<TransitionStep>()
val job = underTest.transition(AOD, LOCKSCREEN).onEach { steps.add(it) }.launchIn(this)
@@ -86,7 +86,7 @@
}
@Test
- fun `starting second transition will cancel the first transition`() =
+ fun startingSecondTransitionWillCancelTheFirstTransition() =
TestScope().runTest {
val steps = mutableListOf<TransitionStep>()
val job = underTest.transition(AOD, LOCKSCREEN).onEach { steps.add(it) }.launchIn(this)
@@ -114,7 +114,7 @@
}
@Test
- fun `Null animator enables manual control with updateTransition`() =
+ fun nullAnimatorEnablesManualControlWithUpdateTransition() =
TestScope().runTest {
val steps = mutableListOf<TransitionStep>()
val job = underTest.transition(AOD, LOCKSCREEN).onEach { steps.add(it) }.launchIn(this)
@@ -146,13 +146,13 @@
}
@Test
- fun `Attempt to manually update transition with invalid UUID throws exception`() {
+ fun attemptTomanuallyUpdateTransitionWithInvalidUUIDthrowsException() {
underTest.updateTransition(UUID.randomUUID(), 0f, TransitionState.RUNNING)
assertThat(wtfHandler.failed).isTrue()
}
@Test
- fun `Attempt to manually update transition after FINISHED state throws exception`() {
+ fun attemptToManuallyUpdateTransitionAfterFINISHEDstateThrowsException() {
val uuid =
underTest.startTransition(
TransitionInfo(
@@ -171,7 +171,7 @@
}
@Test
- fun `Attempt to manually update transition after CANCELED state throws exception`() {
+ fun attemptToManuallyUpdateTransitionAfterCANCELEDstateThrowsException() {
val uuid =
underTest.startTransition(
TransitionInfo(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
index f9493d1..9daf3f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
@@ -48,7 +48,7 @@
}
@Test
- fun `nextRevealEffect - effect switches between default and biometric with no dupes`() =
+ fun nextRevealEffect_effectSwitchesBetweenDefaultAndBiometricWithNoDupes() =
runTest {
val values = mutableListOf<LightRevealEffect>()
val job = launch { underTest.revealEffect.collect { values.add(it) } }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
index 77bb12c..8a0cf4f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
@@ -92,7 +92,7 @@
}
@Test
- fun `isEnabled - always false when quick settings are visible`() =
+ fun isEnabled_alwaysFalseWhenQuickSettingsAreVisible() =
testScope.runTest {
val isEnabled = collectLastValue(underTest.isLongPressHandlingEnabled)
KeyguardState.values().forEach { keyguardState ->
@@ -163,7 +163,7 @@
}
@Test
- fun `long pressed - close dialogs broadcast received - popup dismissed`() =
+ fun longPressed_closeDialogsBroadcastReceived_popupDismissed() =
testScope.runTest {
val isMenuVisible by collectLastValue(underTest.isMenuVisible)
runCurrent()
@@ -211,7 +211,7 @@
}
@Test
- fun `logs when menu is shown`() =
+ fun logsWhenMenuIsShown() =
testScope.runTest {
collectLastValue(underTest.isMenuVisible)
runCurrent()
@@ -223,7 +223,7 @@
}
@Test
- fun `logs when menu is clicked`() =
+ fun logsWhenMenuIsClicked() =
testScope.runTest {
collectLastValue(underTest.isMenuVisible)
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 503e002..96fff64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -195,7 +195,7 @@
}
@Test
- fun `quickAffordance - bottom start affordance is visible`() =
+ fun quickAffordance_bottomStartAffordanceIsVisible() =
testScope.runTest {
val configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS
homeControls.setState(
@@ -221,7 +221,7 @@
}
@Test
- fun `quickAffordance - bottom end affordance is visible`() =
+ fun quickAffordance_bottomEndAffordanceIsVisible() =
testScope.runTest {
val configKey = BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
quickAccessWallet.setState(
@@ -246,7 +246,7 @@
}
@Test
- fun `quickAffordance - hidden when all features are disabled by device policy`() =
+ fun quickAffordance_hiddenWhenAllFeaturesAreDisabledByDevicePolicy() =
testScope.runTest {
whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId))
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)
@@ -265,7 +265,7 @@
}
@Test
- fun `quickAffordance - hidden when shortcuts feature is disabled by device policy`() =
+ fun quickAffordance_hiddenWhenShortcutsFeatureIsDisabledByDevicePolicy() =
testScope.runTest {
whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId))
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL)
@@ -284,7 +284,7 @@
}
@Test
- fun `quickAffordance - hidden when quick settings is visible`() =
+ fun quickAffordance_hiddenWhenQuickSettingsIsVisible() =
testScope.runTest {
repository.setQuickSettingsVisible(true)
quickAccessWallet.setState(
@@ -302,7 +302,7 @@
}
@Test
- fun `quickAffordance - bottom start affordance hidden while dozing`() =
+ fun quickAffordance_bottomStartAffordanceHiddenWhileDozing() =
testScope.runTest {
repository.setDozing(true)
homeControls.setState(
@@ -319,7 +319,7 @@
}
@Test
- fun `quickAffordance - bottom start affordance hidden when lockscreen is not showing`() =
+ fun quickAffordance_bottomStartAffordanceHiddenWhenLockscreenIsNotShowing() =
testScope.runTest {
repository.setKeyguardShowing(false)
homeControls.setState(
@@ -336,7 +336,7 @@
}
@Test
- fun `quickAffordanceAlwaysVisible - even when lock screen not showing and dozing`() =
+ fun quickAffordanceAlwaysVisible_evenWhenLockScreenNotShowingAndDozing() =
testScope.runTest {
repository.setKeyguardShowing(false)
repository.setDozing(true)
@@ -511,7 +511,7 @@
}
@Test
- fun `unselect - one`() =
+ fun unselect_one() =
testScope.runTest {
featureFlags.set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true)
homeControls.setState(
@@ -588,7 +588,7 @@
}
@Test
- fun `unselect - all`() =
+ fun unselect_all() =
testScope.runTest {
featureFlags.set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true)
homeControls.setState(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
index 276b3e3..503687d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -52,7 +52,7 @@
}
@Test
- fun `transition collectors receives only appropriate events`() = runTest {
+ fun transitionCollectorsReceivesOnlyAppropriateEvents() = runTest {
val lockscreenToAodSteps by collectValues(underTest.lockscreenToAodTransition)
val aodToLockscreenSteps by collectValues(underTest.aodToLockscreenTransition)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index e2d0ec3..fe65236 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -180,7 +180,7 @@
}
@Test
- fun `DREAMING to LOCKSCREEN`() =
+ fun DREAMINGtoLOCKSCREEN() =
testScope.runTest {
// GIVEN a device is dreaming
keyguardRepository.setDreamingWithOverlay(true)
@@ -215,7 +215,7 @@
}
@Test
- fun `LOCKSCREEN to PRIMARY_BOUNCER via bouncer showing call`() =
+ fun LOCKSCREENtoPRIMARY_BOUNCERviaBouncerShowingCall() =
testScope.runTest {
// GIVEN a device that has at least woken up
keyguardRepository.setWakefulnessModel(startingToWake())
@@ -242,7 +242,7 @@
}
@Test
- fun `OCCLUDED to DOZING`() =
+ fun OCCLUDEDtoDOZING() =
testScope.runTest {
// GIVEN a device with AOD not available
keyguardRepository.setAodAvailable(false)
@@ -269,7 +269,7 @@
}
@Test
- fun `OCCLUDED to AOD`() =
+ fun OCCLUDEDtoAOD() =
testScope.runTest {
// GIVEN a device with AOD available
keyguardRepository.setAodAvailable(true)
@@ -296,7 +296,7 @@
}
@Test
- fun `LOCKSCREEN to DREAMING`() =
+ fun LOCKSCREENtoDREAMING() =
testScope.runTest {
// GIVEN a device that is not dreaming or dozing
keyguardRepository.setDreamingWithOverlay(false)
@@ -327,7 +327,7 @@
}
@Test
- fun `LOCKSCREEN to DOZING`() =
+ fun LOCKSCREENtoDOZING() =
testScope.runTest {
// GIVEN a device with AOD not available
keyguardRepository.setAodAvailable(false)
@@ -354,7 +354,7 @@
}
@Test
- fun `LOCKSCREEN to AOD`() =
+ fun LOCKSCREENtoAOD() =
testScope.runTest {
// GIVEN a device with AOD available
keyguardRepository.setAodAvailable(true)
@@ -381,7 +381,7 @@
}
@Test
- fun `DOZING to LOCKSCREEN`() =
+ fun DOZINGtoLOCKSCREEN() =
testScope.runTest {
// GIVEN a prior transition has run to DOZING
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.DOZING)
@@ -404,7 +404,7 @@
}
@Test
- fun `DOZING to LOCKSCREEN cannot be interruped by DREAMING`() =
+ fun DOZINGtoLOCKSCREENcannotBeInterrupedByDREAMING() =
testScope.runTest {
// GIVEN a prior transition has started to LOCKSCREEN
transitionRepository.sendTransitionStep(
@@ -430,7 +430,7 @@
}
@Test
- fun `DOZING to GONE`() =
+ fun DOZINGtoGONE() =
testScope.runTest {
// GIVEN a prior transition has run to DOZING
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.DOZING)
@@ -453,7 +453,7 @@
}
@Test
- fun `GONE to DOZING`() =
+ fun GONEtoDOZING() =
testScope.runTest {
// GIVEN a device with AOD not available
keyguardRepository.setAodAvailable(false)
@@ -480,7 +480,7 @@
}
@Test
- fun `GONE to AOD`() =
+ fun GONEtoAOD() =
testScope.runTest {
// GIVEN a device with AOD available
keyguardRepository.setAodAvailable(true)
@@ -507,7 +507,7 @@
}
@Test
- fun `GONE to LOCKSREEN`() =
+ fun GONEtoLOCKSREEN() =
testScope.runTest {
// GIVEN a prior transition has run to GONE
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.GONE)
@@ -530,7 +530,7 @@
}
@Test
- fun `GONE to DREAMING`() =
+ fun GONEtoDREAMING() =
testScope.runTest {
// GIVEN a device that is not dreaming or dozing
keyguardRepository.setDreamingWithOverlay(false)
@@ -561,7 +561,7 @@
}
@Test
- fun `ALTERNATE_BOUNCER to PRIMARY_BOUNCER`() =
+ fun ALTERNATE_BOUNCERtoPRIMARY_BOUNCER() =
testScope.runTest {
// GIVEN a prior transition has run to ALTERNATE_BOUNCER
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.ALTERNATE_BOUNCER)
@@ -584,7 +584,7 @@
}
@Test
- fun `ALTERNATE_BOUNCER to AOD`() =
+ fun ALTERNATE_BOUNCERtoAOD() =
testScope.runTest {
// GIVEN a prior transition has run to ALTERNATE_BOUNCER
bouncerRepository.setAlternateVisible(true)
@@ -613,7 +613,7 @@
}
@Test
- fun `ALTERNATE_BOUNCER to DOZING`() =
+ fun ALTERNATE_BOUNCERtoDOZING() =
testScope.runTest {
// GIVEN a prior transition has run to ALTERNATE_BOUNCER
bouncerRepository.setAlternateVisible(true)
@@ -643,7 +643,7 @@
}
@Test
- fun `ALTERNATE_BOUNCER to LOCKSCREEN`() =
+ fun ALTERNATE_BOUNCERtoLOCKSCREEN() =
testScope.runTest {
// GIVEN a prior transition has run to ALTERNATE_BOUNCER
bouncerRepository.setAlternateVisible(true)
@@ -671,7 +671,7 @@
}
@Test
- fun `PRIMARY_BOUNCER to AOD`() =
+ fun PRIMARY_BOUNCERtoAOD() =
testScope.runTest {
// GIVEN a prior transition has run to PRIMARY_BOUNCER
bouncerRepository.setPrimaryShow(true)
@@ -699,7 +699,7 @@
}
@Test
- fun `PRIMARY_BOUNCER to DOZING`() =
+ fun PRIMARY_BOUNCERtoDOZING() =
testScope.runTest {
// GIVEN a prior transition has run to PRIMARY_BOUNCER
bouncerRepository.setPrimaryShow(true)
@@ -727,7 +727,7 @@
}
@Test
- fun `PRIMARY_BOUNCER to LOCKSCREEN`() =
+ fun PRIMARY_BOUNCERtoLOCKSCREEN() =
testScope.runTest {
// GIVEN a prior transition has run to PRIMARY_BOUNCER
bouncerRepository.setPrimaryShow(true)
@@ -754,7 +754,7 @@
}
@Test
- fun `OCCLUDED to GONE`() =
+ fun OCCLUDEDtoGONE() =
testScope.runTest {
// GIVEN a device on lockscreen
keyguardRepository.setKeyguardShowing(true)
@@ -785,7 +785,7 @@
}
@Test
- fun `OCCLUDED to LOCKSCREEN`() =
+ fun OCCLUDEDtoLOCKSCREEN() =
testScope.runTest {
// GIVEN a device on lockscreen
keyguardRepository.setKeyguardShowing(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
index 6236616..359854b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
@@ -69,7 +69,7 @@
}
@Test
- fun `lightRevealEffect - does not change during keyguard transition`() =
+ fun lightRevealEffect_doesNotChangeDuringKeyguardTransition() =
runTest(UnconfinedTestDispatcher()) {
val values = mutableListOf<LightRevealEffect>()
val job = underTest.lightRevealEffect.onEach(values::add).launchIn(this)
@@ -103,7 +103,7 @@
}
@Test
- fun `revealAmount - inverted when appropriate`() =
+ fun revealAmount_invertedWhenAppropriate() =
runTest(UnconfinedTestDispatcher()) {
val values = mutableListOf<Float>()
val job = underTest.revealAmount.onEach(values::add).launchIn(this)
@@ -132,7 +132,7 @@
}
@Test
- fun `revealAmount - ignores transitions that do not affect reveal amount`() =
+ fun revealAmount_ignoresTransitionsThatDoNotAffectRevealAmount() =
runTest(UnconfinedTestDispatcher()) {
val values = mutableListOf<Float>()
val job = underTest.revealAmount.onEach(values::add).launchIn(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 224eec1..2361c59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -251,7 +251,7 @@
}
@Test
- fun `startButton - present - visible model - starts activity on click`() =
+ fun startButton_present_visibleModel_startsActivityOnClick() =
testScope.runTest {
repository.setKeyguardShowing(true)
val latest = collectLastValue(underTest.startButton)
@@ -280,7 +280,7 @@
}
@Test
- fun `startButton - hidden when device policy disables all keyguard features`() =
+ fun startButton_hiddenWhenDevicePolicyDisablesAllKeyguardFeatures() =
testScope.runTest {
whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId))
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)
@@ -315,7 +315,7 @@
}
@Test
- fun `startButton - in preview mode - visible even when keyguard not showing`() =
+ fun startButton_inPreviewMode_visibleEvenWhenKeyguardNotShowing() =
testScope.runTest {
underTest.enablePreviewMode(
initiallySelectedSlotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
@@ -359,7 +359,7 @@
}
@Test
- fun `endButton - in higlighted preview mode - dimmed when other is selected`() =
+ fun endButton_inHiglightedPreviewMode_dimmedWhenOtherIsSelected() =
testScope.runTest {
underTest.enablePreviewMode(
initiallySelectedSlotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
@@ -416,7 +416,7 @@
}
@Test
- fun `endButton - present - visible model - do nothing on click`() =
+ fun endButton_present_visibleModel_doNothingOnClick() =
testScope.runTest {
repository.setKeyguardShowing(true)
val latest = collectLastValue(underTest.endButton)
@@ -445,7 +445,7 @@
}
@Test
- fun `startButton - not present - model is hidden`() =
+ fun startButton_notPresent_modelIsHidden() =
testScope.runTest {
val latest = collectLastValue(underTest.startButton)
@@ -524,7 +524,7 @@
}
@Test
- fun `alpha - in preview mode - does not change`() =
+ fun alpha_inPreviewMode_doesNotChange() =
testScope.runTest {
underTest.enablePreviewMode(
initiallySelectedSlotId = null,
@@ -629,7 +629,7 @@
}
@Test
- fun `isClickable - true when alpha at threshold`() =
+ fun isClickable_trueWhenAlphaAtThreshold() =
testScope.runTest {
repository.setKeyguardShowing(true)
repository.setBottomAreaAlpha(
@@ -661,7 +661,7 @@
}
@Test
- fun `isClickable - true when alpha above threshold`() =
+ fun isClickable_trueWhenAlphaAboveThreshold() =
testScope.runTest {
repository.setKeyguardShowing(true)
val latest = collectLastValue(underTest.startButton)
@@ -692,7 +692,7 @@
}
@Test
- fun `isClickable - false when alpha below threshold`() =
+ fun isClickable_falseWhenAlphaBelowThreshold() =
testScope.runTest {
repository.setKeyguardShowing(true)
val latest = collectLastValue(underTest.startButton)
@@ -723,7 +723,7 @@
}
@Test
- fun `isClickable - false when alpha at zero`() =
+ fun isClickable_falseWhenAlphaAtZero() =
testScope.runTest {
repository.setKeyguardShowing(true)
val latest = collectLastValue(underTest.startButton)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
index 0c4e845..efa5f0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
@@ -92,6 +92,21 @@
job.cancel()
}
+ @Test
+ fun lockscreenTranslationYResettedAfterJobCancelled() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val pixels = 100
+ val job =
+ underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
+ repository.sendTransitionStep(step(0.5f, TransitionState.CANCELED))
+
+ assertThat(values.last()).isEqualTo(0f)
+
+ job.cancel()
+ }
+
private fun step(
value: Float,
state: TransitionState = TransitionState.RUNNING
diff --git a/packages/SystemUI/tests/src/com/android/systemui/lifecycle/RepeatWhenAttachedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/RepeatWhenAttachedTest.kt
index ea11f01..afab250 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/lifecycle/RepeatWhenAttachedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/RepeatWhenAttachedTest.kt
@@ -88,7 +88,7 @@
}
@Test(expected = IllegalStateException::class)
- fun `repeatWhenAttached - enforces main thread`() =
+ fun repeatWhenAttached_enforcesMainThread() =
testScope.runTest {
Assert.setTestThread(null)
@@ -96,7 +96,7 @@
}
@Test(expected = IllegalStateException::class)
- fun `repeatWhenAttached - dispose enforces main thread`() =
+ fun repeatWhenAttached_disposeEnforcesMainThread() =
testScope.runTest {
val disposableHandle = repeatWhenAttached()
Assert.setTestThread(null)
@@ -105,7 +105,7 @@
}
@Test
- fun `repeatWhenAttached - view starts detached - runs block when attached`() =
+ fun repeatWhenAttached_viewStartsDetached_runsBlockWhenAttached() =
testScope.runTest {
whenever(view.isAttachedToWindow).thenReturn(false)
repeatWhenAttached()
@@ -120,7 +120,7 @@
}
@Test
- fun `repeatWhenAttached - view already attached - immediately runs block`() =
+ fun repeatWhenAttached_viewAlreadyAttached_immediatelyRunsBlock() =
testScope.runTest {
whenever(view.isAttachedToWindow).thenReturn(true)
@@ -132,7 +132,7 @@
}
@Test
- fun `repeatWhenAttached - starts visible without focus - STARTED`() =
+ fun repeatWhenAttached_startsVisibleWithoutFocus_STARTED() =
testScope.runTest {
whenever(view.isAttachedToWindow).thenReturn(true)
whenever(view.windowVisibility).thenReturn(View.VISIBLE)
@@ -145,7 +145,7 @@
}
@Test
- fun `repeatWhenAttached - starts with focus but invisible - CREATED`() =
+ fun repeatWhenAttached_startsWithFocusButInvisible_CREATED() =
testScope.runTest {
whenever(view.isAttachedToWindow).thenReturn(true)
whenever(view.hasWindowFocus()).thenReturn(true)
@@ -158,7 +158,7 @@
}
@Test
- fun `repeatWhenAttached - starts visible and with focus - RESUMED`() =
+ fun repeatWhenAttached_startsVisibleAndWithFocus_RESUMED() =
testScope.runTest {
whenever(view.isAttachedToWindow).thenReturn(true)
whenever(view.windowVisibility).thenReturn(View.VISIBLE)
@@ -172,7 +172,7 @@
}
@Test
- fun `repeatWhenAttached - becomes visible without focus - STARTED`() =
+ fun repeatWhenAttached_becomesVisibleWithoutFocus_STARTED() =
testScope.runTest {
whenever(view.isAttachedToWindow).thenReturn(true)
repeatWhenAttached()
@@ -188,7 +188,7 @@
}
@Test
- fun `repeatWhenAttached - gains focus but invisible - CREATED`() =
+ fun repeatWhenAttached_gainsFocusButInvisible_CREATED() =
testScope.runTest {
whenever(view.isAttachedToWindow).thenReturn(true)
repeatWhenAttached()
@@ -204,7 +204,7 @@
}
@Test
- fun `repeatWhenAttached - becomes visible and gains focus - RESUMED`() =
+ fun repeatWhenAttached_becomesVisibleAndGainsFocus_RESUMED() =
testScope.runTest {
whenever(view.isAttachedToWindow).thenReturn(true)
repeatWhenAttached()
@@ -224,7 +224,7 @@
}
@Test
- fun `repeatWhenAttached - view gets detached - destroys the lifecycle`() =
+ fun repeatWhenAttached_viewGetsDetached_destroysTheLifecycle() =
testScope.runTest {
whenever(view.isAttachedToWindow).thenReturn(true)
repeatWhenAttached()
@@ -238,7 +238,7 @@
}
@Test
- fun `repeatWhenAttached - view gets reattached - recreates a lifecycle`() =
+ fun repeatWhenAttached_viewGetsReattached_recreatesAlifecycle() =
testScope.runTest {
whenever(view.isAttachedToWindow).thenReturn(true)
repeatWhenAttached()
@@ -255,7 +255,7 @@
}
@Test
- fun `repeatWhenAttached - dispose attached`() =
+ fun repeatWhenAttached_disposeAttached() =
testScope.runTest {
whenever(view.isAttachedToWindow).thenReturn(true)
val handle = repeatWhenAttached()
@@ -269,7 +269,7 @@
}
@Test
- fun `repeatWhenAttached - dispose never attached`() =
+ fun repeatWhenAttached_disposeNeverAttached() =
testScope.runTest {
whenever(view.isAttachedToWindow).thenReturn(false)
val handle = repeatWhenAttached()
@@ -281,7 +281,7 @@
}
@Test
- fun `repeatWhenAttached - dispose previously attached now detached`() =
+ fun repeatWhenAttached_disposePreviouslyAttachedNowDetached() =
testScope.runTest {
whenever(view.isAttachedToWindow).thenReturn(true)
val handle = repeatWhenAttached()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt
index 411b1bd..af83a56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt
@@ -31,7 +31,7 @@
private val underTest = TableLogBufferFactory(dumpManager, systemClock)
@Test
- fun `create - always creates new instance`() {
+ fun create_alwaysCreatesNewInstance() {
val b1 = underTest.create(NAME_1, SIZE)
val b1_copy = underTest.create(NAME_1, SIZE)
val b2 = underTest.create(NAME_2, SIZE)
@@ -43,7 +43,7 @@
}
@Test
- fun `getOrCreate - reuses instance`() {
+ fun getOrCreate_reusesInstance() {
val b1 = underTest.getOrCreate(NAME_1, SIZE)
val b1_copy = underTest.getOrCreate(NAME_1, SIZE)
val b2 = underTest.getOrCreate(NAME_2, SIZE)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
index a03bc1e..7dc622b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
@@ -98,7 +98,7 @@
whenever(context.getString(R.string.note_task_button_label))
.thenReturn(NOTE_TASK_SHORT_LABEL)
whenever(context.packageManager).thenReturn(packageManager)
- whenever(resolver.resolveInfo(any(), any())).thenReturn(NOTE_TASK_INFO)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(NOTE_TASK_INFO)
whenever(userManager.isUserUnlocked).thenReturn(true)
whenever(
devicePolicyManager.getKeyguardDisabledFeatures(
@@ -142,7 +142,7 @@
.apply { infoReference.set(expectedInfo) }
.onBubbleExpandChanged(
isExpanding = true,
- key = Bubble.KEY_APP_BUBBLE,
+ key = Bubble.getAppBubbleKeyForApp(expectedInfo.packageName, expectedInfo.user),
)
verify(eventLogger).logNoteTaskOpened(expectedInfo)
@@ -157,7 +157,7 @@
.apply { infoReference.set(expectedInfo) }
.onBubbleExpandChanged(
isExpanding = false,
- key = Bubble.KEY_APP_BUBBLE,
+ key = Bubble.getAppBubbleKeyForApp(expectedInfo.packageName, expectedInfo.user),
)
verify(eventLogger).logNoteTaskClosed(expectedInfo)
@@ -172,7 +172,7 @@
.apply { infoReference.set(expectedInfo) }
.onBubbleExpandChanged(
isExpanding = true,
- key = Bubble.KEY_APP_BUBBLE,
+ key = Bubble.getAppBubbleKeyForApp(expectedInfo.packageName, expectedInfo.user),
)
verifyZeroInteractions(context, bubbles, keyguardManager, userManager, eventLogger)
@@ -186,7 +186,7 @@
.apply { infoReference.set(expectedInfo) }
.onBubbleExpandChanged(
isExpanding = false,
- key = Bubble.KEY_APP_BUBBLE,
+ key = Bubble.getAppBubbleKeyForApp(expectedInfo.packageName, expectedInfo.user),
)
verifyZeroInteractions(context, bubbles, keyguardManager, userManager, eventLogger)
@@ -208,7 +208,7 @@
createNoteTaskController(isEnabled = false)
.onBubbleExpandChanged(
isExpanding = true,
- key = Bubble.KEY_APP_BUBBLE,
+ key = Bubble.getAppBubbleKeyForApp(NOTE_TASK_INFO.packageName, NOTE_TASK_INFO.user),
)
verifyZeroInteractions(context, bubbles, keyguardManager, userManager, eventLogger)
@@ -224,7 +224,7 @@
isKeyguardLocked = true,
)
whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
- whenever(resolver.resolveInfo(any(), any())).thenReturn(expectedInfo)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
createNoteTaskController()
.showNoteTask(
@@ -256,9 +256,10 @@
NOTE_TASK_INFO.copy(
entryPoint = NoteTaskEntryPoint.TAIL_BUTTON,
isKeyguardLocked = true,
+ user = user10,
)
whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
- whenever(resolver.resolveInfo(any(), any())).thenReturn(expectedInfo)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
createNoteTaskController()
.showNoteTaskAsUser(
@@ -292,7 +293,7 @@
isKeyguardLocked = true,
)
whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
- whenever(resolver.resolveInfo(any(), any())).thenReturn(expectedInfo)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
whenever(activityManager.getRunningTasks(anyInt()))
.thenReturn(listOf(NOTE_RUNNING_TASK_INFO))
@@ -318,7 +319,7 @@
entryPoint = NoteTaskEntryPoint.TAIL_BUTTON,
isKeyguardLocked = false,
)
- whenever(resolver.resolveInfo(any(), any())).thenReturn(expectedInfo)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
createNoteTaskController()
@@ -344,7 +345,7 @@
@Test
fun showNoteTask_intentResolverReturnsNull_shouldShowToast() {
- whenever(resolver.resolveInfo(any(), any())).thenReturn(null)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(null)
val noteTaskController = spy(createNoteTaskController())
doNothing().whenever(noteTaskController).showNoDefaultNotesAppToast()
@@ -384,7 +385,7 @@
isKeyguardLocked = true,
)
whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
- whenever(resolver.resolveInfo(any(), any())).thenReturn(expectedInfo)
+ whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
createNoteTaskController()
.showNoteTask(
@@ -717,6 +718,7 @@
NoteTaskInfo(
packageName = NOTE_TASK_PACKAGE_NAME,
uid = NOTE_TASK_UID,
+ user = UserHandle.of(0),
)
private val NOTE_RUNNING_TASK_INFO =
ActivityManager.RunningTaskInfo().apply {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskEventLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskEventLoggerTest.kt
index a4df346..b4f5528 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskEventLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskEventLoggerTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.notetask
+import android.os.UserHandle
import android.test.suitebuilder.annotation.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.internal.logging.UiEventLogger
@@ -44,7 +45,7 @@
NoteTaskEventLogger(uiEventLogger)
private fun createNoteTaskInfo(): NoteTaskInfo =
- NoteTaskInfo(packageName = NOTES_PACKAGE_NAME, uid = NOTES_UID)
+ NoteTaskInfo(packageName = NOTES_PACKAGE_NAME, uid = NOTES_UID, UserHandle.of(0))
@Before
fun setUp() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoResolverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoResolverTest.kt
index 0c945df..e09c804 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoResolverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoResolverTest.kt
@@ -22,8 +22,6 @@
import android.test.suitebuilder.annotation.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.systemui.SysuiTestCase
-import com.android.systemui.settings.FakeUserTracker
-import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -46,14 +44,13 @@
@Mock lateinit var packageManager: PackageManager
@Mock lateinit var roleManager: RoleManager
- private val userTracker: UserTracker = FakeUserTracker()
private lateinit var underTest: NoteTaskInfoResolver
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- underTest = NoteTaskInfoResolver(roleManager, packageManager, userTracker)
+ underTest = NoteTaskInfoResolver(roleManager, packageManager)
}
@Test
@@ -72,11 +69,12 @@
)
.thenReturn(ApplicationInfo().apply { this.uid = uid })
- val actual = underTest.resolveInfo()
+ val actual = underTest.resolveInfo(user = context.user)
requireNotNull(actual) { "Note task info must not be null" }
assertThat(actual.packageName).isEqualTo(packageName)
assertThat(actual.uid).isEqualTo(uid)
+ assertThat(actual.user).isEqualTo(context.user)
}
@Test
@@ -94,11 +92,12 @@
)
.thenThrow(PackageManager.NameNotFoundException(packageName))
- val actual = underTest.resolveInfo()
+ val actual = underTest.resolveInfo(user = context.user)
requireNotNull(actual) { "Note task info must not be null" }
assertThat(actual.packageName).isEqualTo(packageName)
assertThat(actual.uid).isEqualTo(0)
+ assertThat(actual.user).isEqualTo(context.user)
}
@Test
@@ -107,7 +106,7 @@
emptyList<String>()
}
- val actual = underTest.resolveInfo()
+ val actual = underTest.resolveInfo(user = context.user)
assertThat(actual).isNull()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
index 91cd6ae..3435450 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.notetask
+import android.os.UserHandle
import android.test.suitebuilder.annotation.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.systemui.SysuiTestCase
@@ -28,7 +29,7 @@
internal class NoteTaskInfoTest : SysuiTestCase() {
private fun createNoteTaskInfo(): NoteTaskInfo =
- NoteTaskInfo(packageName = NOTES_PACKAGE_NAME, uid = NOTES_UID)
+ NoteTaskInfo(packageName = NOTES_PACKAGE_NAME, uid = NOTES_UID, UserHandle.of(0))
@Test
fun launchMode_keyguardLocked_launchModeActivity() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
index 249a91b..bb3b3f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
@@ -66,7 +66,7 @@
}
@Test
- fun `isInteractive - registers for broadcasts`() =
+ fun isInteractive_registersForBroadcasts() =
runBlocking(IMMEDIATE) {
val job = underTest.isInteractive.onEach {}.launchIn(this)
@@ -78,7 +78,7 @@
}
@Test
- fun `isInteractive - unregisters from broadcasts`() =
+ fun isInteractive_unregistersFromBroadcasts() =
runBlocking(IMMEDIATE) {
val job = underTest.isInteractive.onEach {}.launchIn(this)
verifyRegistered()
@@ -89,7 +89,7 @@
}
@Test
- fun `isInteractive - emits initial true value if screen was on`() =
+ fun isInteractive_emitsInitialTrueValueIfScreenWasOn() =
runBlocking(IMMEDIATE) {
isInteractive = true
var value: Boolean? = null
@@ -102,7 +102,7 @@
}
@Test
- fun `isInteractive - emits initial false value if screen was off`() =
+ fun isInteractive_emitsInitialFalseValueIfScreenWasOff() =
runBlocking(IMMEDIATE) {
isInteractive = false
var value: Boolean? = null
@@ -115,7 +115,7 @@
}
@Test
- fun `isInteractive - emits true when the screen turns on`() =
+ fun isInteractive_emitsTrueWhenTheScreenTurnsOn() =
runBlocking(IMMEDIATE) {
var value: Boolean? = null
val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
@@ -129,7 +129,7 @@
}
@Test
- fun `isInteractive - emits false when the screen turns off`() =
+ fun isInteractive_emitsFalseWhenTheScreenTurnsOff() =
runBlocking(IMMEDIATE) {
var value: Boolean? = null
val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
@@ -143,7 +143,7 @@
}
@Test
- fun `isInteractive - emits correctly over time`() =
+ fun isInteractive_emitsCorrectlyOverTime() =
runBlocking(IMMEDIATE) {
val values = mutableListOf<Boolean>()
val job = underTest.isInteractive.onEach(values::add).launchIn(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
index bf6a37e..31d4512 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
@@ -47,7 +47,7 @@
}
@Test
- fun `isInteractive - screen turns off`() =
+ fun isInteractive_screenTurnsOff() =
runBlocking(IMMEDIATE) {
repository.setInteractive(true)
var value: Boolean? = null
@@ -60,7 +60,7 @@
}
@Test
- fun `isInteractive - becomes interactive`() =
+ fun isInteractive_becomesInteractive() =
runBlocking(IMMEDIATE) {
repository.setInteractive(false)
var value: Boolean? = null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
index 8cb5d31..355c4b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
@@ -153,7 +153,7 @@
}
@Test
- fun `WakefulnessLifecycle - dispatchFinishedWakingUp sets SysUI flag to AWAKE`() {
+ fun wakefulnessLifecycle_dispatchFinishedWakingUpSetsSysUIflagToAWAKE() {
// WakefulnessLifecycle is initialized to AWAKE initially, and won't emit a noop.
wakefulnessLifecycle.dispatchFinishedGoingToSleep()
clearInvocations(overviewProxy)
@@ -167,7 +167,7 @@
}
@Test
- fun `WakefulnessLifecycle - dispatchStartedWakingUp sets SysUI flag to WAKING`() {
+ fun wakefulnessLifecycle_dispatchStartedWakingUpSetsSysUIflagToWAKING() {
wakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN)
verify(overviewProxy)
@@ -177,7 +177,7 @@
}
@Test
- fun `WakefulnessLifecycle - dispatchFinishedGoingToSleep sets SysUI flag to ASLEEP`() {
+ fun wakefulnessLifecycle_dispatchFinishedGoingToSleepSetsSysUIflagToASLEEP() {
wakefulnessLifecycle.dispatchFinishedGoingToSleep()
verify(overviewProxy)
@@ -187,7 +187,7 @@
}
@Test
- fun `WakefulnessLifecycle - dispatchStartedGoingToSleep sets SysUI flag to GOING_TO_SLEEP`() {
+ fun wakefulnessLifecycle_dispatchStartedGoingToSleepSetsSysUIflagToGOING_TO_SLEEP() {
wakefulnessLifecycle.dispatchStartedGoingToSleep(
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
index 57b6b2b..beb981d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
@@ -73,7 +73,7 @@
}
@Test
- fun `calls callback and updates profiles when an intent received`() {
+ fun callsCallbackAndUpdatesProfilesWhenAnIntentReceived() {
tracker.initialize(0)
tracker.addCallback(callback, executor)
val profileID = tracker.userId + 10
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
index b547318..d421aca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
@@ -54,7 +54,7 @@
}
@Test
- fun `returns MODE_ON for qqs with center cutout`() {
+ fun returnsMODE_ONforQqsWithCenterCutout() {
assertThat(
controller.getBatteryMode(CENTER_TOP_CUTOUT, QQS_START_FRAME.prevFrameToFraction())
)
@@ -62,13 +62,13 @@
}
@Test
- fun `returns MODE_ESTIMATE for qs with center cutout`() {
+ fun returnsMODE_ESTIMATEforQsWithCenterCutout() {
assertThat(controller.getBatteryMode(CENTER_TOP_CUTOUT, QS_END_FRAME.nextFrameToFraction()))
.isEqualTo(BatteryMeterView.MODE_ESTIMATE)
}
@Test
- fun `returns MODE_ON for qqs with corner cutout`() {
+ fun returnsMODE_ONforQqsWithCornerCutout() {
whenever(insetsProvider.currentRotationHasCornerCutout()).thenReturn(true)
assertThat(
@@ -78,7 +78,7 @@
}
@Test
- fun `returns MODE_ESTIMATE for qs with corner cutout`() {
+ fun returnsMODE_ESTIMATEforQsWithCornerCutout() {
whenever(insetsProvider.currentRotationHasCornerCutout()).thenReturn(true)
assertThat(controller.getBatteryMode(CENTER_TOP_CUTOUT, QS_END_FRAME.nextFrameToFraction()))
@@ -86,7 +86,7 @@
}
@Test
- fun `returns null in-between`() {
+ fun returnsNullInBetween() {
assertThat(
controller.getBatteryMode(CENTER_TOP_CUTOUT, QQS_START_FRAME.nextFrameToFraction())
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
index 76f7401..9fe75ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
@@ -366,7 +366,7 @@
}
@Test
- fun `battery mode controller called when qsExpandedFraction changes`() {
+ fun batteryModeControllerCalledWhenQsExpandedFractionChanges() {
whenever(qsBatteryModeController.getBatteryMode(Mockito.same(null), eq(0f)))
.thenReturn(BatteryMeterView.MODE_ON)
whenever(qsBatteryModeController.getBatteryMode(Mockito.same(null), eq(1f)))
@@ -825,7 +825,7 @@
}
@Test
- fun `carrier left padding is set when clock layout changes`() {
+ fun carrierLeftPaddingIsSetWhenClockLayoutChanges() {
val width = 200
whenever(clock.width).thenReturn(width)
whenever(clock.scaleX).thenReturn(2.57f) // 2.57 comes from qs_header.xml
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
index 7fa27f3..3f3faf7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
@@ -201,7 +201,7 @@
@Test
fun test_aodClock_always_whiteColor() {
val clock = provider.createClock(DEFAULT_CLOCK_ID)
- clock.animations.doze(0.9f) // set AOD mode to active
+ clock.smallClock.animations.doze(0.9f) // set AOD mode to active
clock.smallClock.events.onRegionDarknessChanged(true)
verify((clock.smallClock.view as AnimatableClockView), never()).animateAppearOnLockscreen()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
index 9d6ea85..b997f64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
@@ -16,11 +16,34 @@
package com.android.systemui.statusbar
+import android.app.Notification
+import android.app.WallpaperManager
+import android.graphics.Bitmap
+import android.media.MediaMetadata
+import android.media.session.MediaSession
+import android.media.session.PlaybackState
import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.colorextraction.SysuiColorExtractor
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.controls.pipeline.MediaDataManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.notification.collection.NotifCollection
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.whenever
-import org.junit.After
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import dagger.Lazy
+import java.util.Optional
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -32,39 +55,121 @@
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-/**
- * Temporary test for the lock screen live wallpaper project.
- *
- * TODO(b/273443374): remove this test
- */
@RunWith(AndroidTestingRunner::class)
@SmallTest
+@RunWithLooper
class NotificationMediaManagerTest : SysuiTestCase() {
- @Mock private lateinit var notificationMediaManager: NotificationMediaManager
+ @Mock private lateinit var centralSurfaces: CentralSurfaces
+ @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
+ @Mock private lateinit var visibilityProvider: NotificationVisibilityProvider
+ @Mock private lateinit var mediaArtworkProcessor: MediaArtworkProcessor
+ @Mock private lateinit var keyguardBypassController: KeyguardBypassController
+ @Mock private lateinit var notifPipeline: NotifPipeline
+ @Mock private lateinit var notifCollection: NotifCollection
+ @Mock private lateinit var mediaDataManager: MediaDataManager
+ @Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var colorExtractor: SysuiColorExtractor
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
+ @Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var wallpaperManager: WallpaperManager
+ @Mock private lateinit var notificationEntry: NotificationEntry
+
+ lateinit var manager: NotificationMediaManager
+ val clock = FakeSystemClock()
+ val mainExecutor: DelayableExecutor = FakeExecutor(clock)
+
+ @Mock private lateinit var mockManager: NotificationMediaManager
@Mock private lateinit var mockBackDropView: BackDropView
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- doCallRealMethod()
- .whenever(notificationMediaManager)
- .updateMediaMetaData(anyBoolean(), anyBoolean())
- doReturn(mockBackDropView).whenever(notificationMediaManager).backDropView
+ doCallRealMethod().whenever(mockManager).updateMediaMetaData(anyBoolean(), anyBoolean())
+ doReturn(mockBackDropView).whenever(mockManager).backDropView
+
+ manager =
+ NotificationMediaManager(
+ context,
+ Lazy { Optional.of(centralSurfaces) },
+ Lazy { notificationShadeWindowController },
+ visibilityProvider,
+ mediaArtworkProcessor,
+ keyguardBypassController,
+ notifPipeline,
+ notifCollection,
+ mainExecutor,
+ mediaDataManager,
+ statusBarStateController,
+ colorExtractor,
+ keyguardStateController,
+ dumpManager,
+ wallpaperManager,
+ )
}
- @After fun tearDown() {}
-
- /** Check that updateMediaMetaData is a no-op with mIsLockscreenLiveWallpaperEnabled = true */
+ /**
+ * Check that updateMediaMetaData is a no-op with mIsLockscreenLiveWallpaperEnabled = true
+ * Temporary test for the lock screen live wallpaper project.
+ *
+ * TODO(b/273443374): remove this test
+ */
@Test
fun testUpdateMediaMetaDataDisabled() {
- notificationMediaManager.mIsLockscreenLiveWallpaperEnabled = true
+ mockManager.mIsLockscreenLiveWallpaperEnabled = true
for (metaDataChanged in listOf(true, false)) {
for (allowEnterAnimation in listOf(true, false)) {
- notificationMediaManager.updateMediaMetaData(metaDataChanged, allowEnterAnimation)
- verify(notificationMediaManager, never()).mediaMetadata
+ mockManager.updateMediaMetaData(metaDataChanged, allowEnterAnimation)
+ verify(mockManager, never()).mediaMetadata
}
}
}
+
+ @Test
+ fun testMetadataUpdated_doesNotRetainArtwork() {
+ val artBmp = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
+ val artUri = "content://example"
+ val inputMetadata =
+ MediaMetadata.Builder()
+ .putBitmap(MediaMetadata.METADATA_KEY_ART, artBmp)
+ .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, artBmp)
+ .putBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON, artBmp)
+ .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, artUri)
+ .putString(MediaMetadata.METADATA_KEY_ART_URI, artUri)
+ .putString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, artUri)
+ .build()
+
+ // Create a playing media notification
+ val state = PlaybackState.Builder().setState(PlaybackState.STATE_PLAYING, 0L, 1f).build()
+ val session = MediaSession(context, "NotificationMediaManagerTest")
+ session.setMetadata(inputMetadata)
+ session.setPlaybackState(state)
+ val sbn =
+ SbnBuilder().run {
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_play)
+ it.setStyle(
+ Notification.MediaStyle().apply { setMediaSession(session.sessionToken) }
+ )
+ }
+ build()
+ }
+ whenever(notificationEntry.sbn).thenReturn(sbn)
+ val collection = ArrayList<NotificationEntry>()
+ collection.add(notificationEntry)
+ whenever(notifPipeline.allNotifs).thenReturn(collection)
+
+ // Trigger update in NotificationMediaManager
+ manager.findAndUpdateMediaNotifications()
+
+ // Verify that there is no artwork data retained
+ val metadata = manager.mediaMetadata
+ assertThat(metadata.getBitmap(MediaMetadata.METADATA_KEY_ART)).isNull()
+ assertThat(metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)).isNull()
+ assertThat(metadata.getBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON)).isNull()
+ assertThat(metadata.getString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI)).isNull()
+ assertThat(metadata.getString(MediaMetadata.METADATA_KEY_ART_URI)).isNull()
+ assertThat(metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI)).isNull()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt
index 63cb30c..95b132d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt
@@ -39,7 +39,7 @@
}
@Test
- fun `process new config - reflected by isUsingDefault`() {
+ fun processNewConfig_reflectedByIsUsingDefault() {
// Starts out using the defaults
assertThat(underTest.isUsingDefault).isTrue()
@@ -50,7 +50,7 @@
}
@Test
- fun `process new config - updates all flows`() {
+ fun processNewConfig_updatesAllFlows() {
assertThat(underTest.shouldInflateSignalStrength.value).isFalse()
assertThat(underTest.showOperatorNameInStatusBar.value).isFalse()
@@ -66,7 +66,7 @@
}
@Test
- fun `process new config - defaults to false for config overrides`() {
+ fun processNewConfig_defaultsToFalseForConfigOverrides() {
// This case is only apparent when:
// 1. The default is true
// 2. The override config has no value for a given key
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
index dfef62e..6e3af26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
@@ -96,7 +96,7 @@
}
@Test
- fun `carrier config stream produces int-bundle pairs`() =
+ fun carrierConfigStreamProducesIntBundlePairs() =
testScope.runTest {
var latest: Pair<Int, PersistableBundle>? = null
val job = underTest.carrierConfigStream.onEach { latest = it }.launchIn(this)
@@ -111,7 +111,7 @@
}
@Test
- fun `carrier config stream ignores invalid subscriptions`() =
+ fun carrierConfigStreamIgnoresInvalidSubscriptions() =
testScope.runTest {
var latest: Pair<Int, PersistableBundle>? = null
val job = underTest.carrierConfigStream.onEach { latest = it }.launchIn(this)
@@ -124,19 +124,19 @@
}
@Test
- fun `getOrCreateConfig - uses default config if no override`() {
+ fun getOrCreateConfig_usesDefaultConfigIfNoOverride() {
val config = underTest.getOrCreateConfigForSubId(123)
assertThat(config.isUsingDefault).isTrue()
}
@Test
- fun `getOrCreateConfig - uses override if exists`() {
+ fun getOrCreateConfig_usesOverrideIfExists() {
val config = underTest.getOrCreateConfigForSubId(SUB_ID_1)
assertThat(config.isUsingDefault).isFalse()
}
@Test
- fun `config - updates while config stream is collected`() =
+ fun config_updatesWhileConfigStreamIsCollected() =
testScope.runTest {
CONFIG_1.putBoolean(CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
index 1fdcf7f..3ec9690 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
@@ -156,7 +156,7 @@
}
@Test
- fun `active repo matches demo mode setting`() =
+ fun activeRepoMatchesDemoModeSetting() =
runBlocking(IMMEDIATE) {
whenever(demoModeController.isInDemoMode).thenReturn(false)
@@ -177,7 +177,7 @@
}
@Test
- fun `subscription list updates when demo mode changes`() =
+ fun subscriptionListUpdatesWhenDemoModeChanges() =
runBlocking(IMMEDIATE) {
whenever(demoModeController.isInDemoMode).thenReturn(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
index 47f8cd3..1251dfa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
@@ -105,7 +105,7 @@
}
@Test
- fun `network event - create new subscription`() =
+ fun networkEvent_createNewSubscription() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
@@ -121,7 +121,7 @@
}
@Test
- fun `wifi carrier merged event - create new subscription`() =
+ fun wifiCarrierMergedEvent_createNewSubscription() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
@@ -137,7 +137,7 @@
}
@Test
- fun `network event - reuses subscription when same Id`() =
+ fun networkEvent_reusesSubscriptionWhenSameId() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
@@ -159,7 +159,7 @@
}
@Test
- fun `wifi carrier merged event - reuses subscription when same Id`() =
+ fun wifiCarrierMergedEvent_reusesSubscriptionWhenSameId() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
@@ -181,7 +181,7 @@
}
@Test
- fun `multiple subscriptions`() =
+ fun multipleSubscriptions() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
@@ -195,7 +195,7 @@
}
@Test
- fun `mobile subscription and carrier merged subscription`() =
+ fun mobileSubscriptionAndCarrierMergedSubscription() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
@@ -209,7 +209,7 @@
}
@Test
- fun `multiple mobile subscriptions and carrier merged subscription`() =
+ fun multipleMobileSubscriptionsAndCarrierMergedSubscription() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
@@ -224,7 +224,7 @@
}
@Test
- fun `mobile disabled event - disables connection - subId specified - single conn`() =
+ fun mobileDisabledEvent_disablesConnection_subIdSpecified_singleConn() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
@@ -239,7 +239,7 @@
}
@Test
- fun `mobile disabled event - disables connection - subId not specified - single conn`() =
+ fun mobileDisabledEvent_disablesConnection_subIdNotSpecified_singleConn() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
@@ -254,7 +254,7 @@
}
@Test
- fun `mobile disabled event - disables connection - subId specified - multiple conn`() =
+ fun mobileDisabledEvent_disablesConnection_subIdSpecified_multipleConn() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
@@ -270,7 +270,7 @@
}
@Test
- fun `mobile disabled event - subId not specified - multiple conn - ignores command`() =
+ fun mobileDisabledEvent_subIdNotSpecified_multipleConn_ignoresCommand() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
@@ -286,7 +286,7 @@
}
@Test
- fun `wifi network updates to disabled - carrier merged connection removed`() =
+ fun wifiNetworkUpdatesToDisabled_carrierMergedConnectionRemoved() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
@@ -303,7 +303,7 @@
}
@Test
- fun `wifi network updates to active - carrier merged connection removed`() =
+ fun wifiNetworkUpdatesToActive_carrierMergedConnectionRemoved() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
@@ -326,7 +326,7 @@
}
@Test
- fun `mobile sub updates to carrier merged - only one connection`() =
+ fun mobileSubUpdatesToCarrierMerged_onlyOneConnection() =
testScope.runTest {
var latestSubsList: List<SubscriptionModel>? = null
var connections: List<DemoMobileConnectionRepository>? = null
@@ -352,7 +352,7 @@
}
@Test
- fun `mobile sub updates to carrier merged then back - has old mobile data`() =
+ fun mobileSubUpdatesToCarrierMergedThenBack_hasOldMobileData() =
testScope.runTest {
var latestSubsList: List<SubscriptionModel>? = null
var connections: List<DemoMobileConnectionRepository>? = null
@@ -393,7 +393,7 @@
/** Regression test for b/261706421 */
@Test
- fun `multiple connections - remove all - does not throw`() =
+ fun multipleConnections_removeAll_doesNotThrow() =
testScope.runTest {
var latest: List<SubscriptionModel>? = null
val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
@@ -411,7 +411,7 @@
}
@Test
- fun `demo connection - single subscription`() =
+ fun demoConnection_singleSubscription() =
testScope.runTest {
var currentEvent: FakeNetworkEventModel = validMobileEvent(subId = 1)
var connections: List<DemoMobileConnectionRepository>? = null
@@ -440,7 +440,7 @@
}
@Test
- fun `demo connection - two connections - update second - no affect on first`() =
+ fun demoConnection_twoConnections_updateSecond_noAffectOnFirst() =
testScope.runTest {
var currentEvent1 = validMobileEvent(subId = 1)
var connection1: DemoMobileConnectionRepository? = null
@@ -487,7 +487,7 @@
}
@Test
- fun `demo connection - two connections - update carrier merged - no affect on first`() =
+ fun demoConnection_twoConnections_updateCarrierMerged_noAffectOnFirst() =
testScope.runTest {
var currentEvent1 = validMobileEvent(subId = 1)
var connection1: DemoMobileConnectionRepository? = null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
index 423c476..9f77744 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
@@ -292,7 +292,7 @@
}
@Test
- fun `factory - reuses log buffers for same connection`() =
+ fun factory_reusesLogBuffersForSameConnection() =
testScope.runTest {
val realLoggerFactory = TableLogBufferFactory(mock(), FakeSystemClock())
@@ -327,7 +327,7 @@
}
@Test
- fun `factory - reuses log buffers for same sub ID even if carrier merged`() =
+ fun factory_reusesLogBuffersForSameSubIDevenIfCarrierMerged() =
testScope.runTest {
val realLoggerFactory = TableLogBufferFactory(mock(), FakeSystemClock())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index 8d7f0f6..c276865 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -353,7 +353,7 @@
}
@Test
- fun `isInService - uses repository value`() =
+ fun isInService_usesRepositoryValue() =
testScope.runTest {
var latest: Boolean? = null
val job = underTest.isInService.onEach { latest = it }.launchIn(this)
@@ -370,7 +370,7 @@
}
@Test
- fun `roaming - is gsm - uses connection model`() =
+ fun roaming_isGsm_usesConnectionModel() =
testScope.runTest {
var latest: Boolean? = null
val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
@@ -389,7 +389,7 @@
}
@Test
- fun `roaming - is cdma - uses cdma roaming bit`() =
+ fun roaming_isCdma_usesCdmaRoamingBit() =
testScope.runTest {
var latest: Boolean? = null
val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
@@ -410,7 +410,7 @@
}
@Test
- fun `roaming - false while carrierNetworkChangeActive`() =
+ fun roaming_falseWhileCarrierNetworkChangeActive() =
testScope.runTest {
var latest: Boolean? = null
val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
@@ -431,7 +431,7 @@
}
@Test
- fun `network name - uses operatorAlphaShot when non null and repo is default`() =
+ fun networkName_usesOperatorAlphaShotWhenNonNullAndRepoIsDefault() =
testScope.runTest {
var latest: NetworkNameModel? = null
val job = underTest.networkName.onEach { latest = it }.launchIn(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index dc68386..c84c9c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -520,7 +520,7 @@
// is private and can only be tested by looking at [isDefaultConnectionFailed].
@Test
- fun `data switch - in same group - validated matches previous value - expires after 2s`() =
+ fun dataSwitch_inSameGroup_validatedMatchesPreviousValue_expiresAfter2s() =
testScope.runTest {
var latestConnectionFailed: Boolean? = null
val job =
@@ -548,7 +548,7 @@
}
@Test
- fun `data switch - in same group - not validated - immediately marked as failed`() =
+ fun dataSwitch_inSameGroup_notValidated_immediatelyMarkedAsFailed() =
testScope.runTest {
var latestConnectionFailed: Boolean? = null
val job =
@@ -567,7 +567,7 @@
}
@Test
- fun `data switch - lose validation - then switch happens - clears forced bit`() =
+ fun dataSwitch_loseValidation_thenSwitchHappens_clearsForcedBit() =
testScope.runTest {
var latestConnectionFailed: Boolean? = null
val job =
@@ -602,7 +602,7 @@
}
@Test
- fun `data switch - while already forcing validation - resets clock`() =
+ fun dataSwitch_whileAlreadyForcingValidation_resetsClock() =
testScope.runTest {
var latestConnectionFailed: Boolean? = null
val job =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
index e99be86..d5fb577 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
@@ -92,7 +92,7 @@
}
@Test
- fun `location based view models receive same icon id when common impl updates`() =
+ fun locationBasedViewModelsReceiveSameIconIdWhenCommonImplUpdates() =
testScope.runTest {
var latestHome: SignalIconModel? = null
val homeJob = homeIcon.icon.onEach { latestHome = it }.launchIn(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
index 297cb9d..2b7bc78 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
@@ -249,7 +249,7 @@
}
@Test
- fun `icon - uses empty state - when not in service`() =
+ fun icon_usesEmptyState_whenNotInService() =
testScope.runTest {
var latest: SignalIconModel? = null
val job = underTest.icon.onEach { latest = it }.launchIn(this)
@@ -480,7 +480,7 @@
}
@Test
- fun `network type - alwaysShow - shown when not default`() =
+ fun networkType_alwaysShow_shownWhenNotDefault() =
testScope.runTest {
interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
interactor.mobileIsDefault.value = false
@@ -500,7 +500,7 @@
}
@Test
- fun `network type - not shown when not default`() =
+ fun networkType_notShownWhenNotDefault() =
testScope.runTest {
interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
interactor.isDataConnected.value = true
@@ -531,7 +531,7 @@
}
@Test
- fun `data activity - null when config is off`() =
+ fun dataActivity_nullWhenConfigIsOff() =
testScope.runTest {
// Create a new view model here so the constants are properly read
whenever(constants.shouldShowActivityConfig).thenReturn(false)
@@ -563,7 +563,7 @@
}
@Test
- fun `data activity - config on - test indicators`() =
+ fun dataActivity_configOn_testIndicators() =
testScope.runTest {
// Create a new view model here so the constants are properly read
whenever(constants.shouldShowActivityConfig).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
index f8e1aa9..f0458fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
@@ -111,7 +111,7 @@
}
@Test
- fun `caching - mobile icon view model is reused for same sub id`() =
+ fun caching_mobileIconViewModelIsReusedForSameSubId() =
testScope.runTest {
val model1 = underTest.viewModelForSub(1, StatusBarLocation.HOME)
val model2 = underTest.viewModelForSub(1, StatusBarLocation.QS)
@@ -120,7 +120,7 @@
}
@Test
- fun `caching - invalid view models are removed from cache when sub disappears`() =
+ fun caching_invalidViewModelsAreRemovedFromCacheWhenSubDisappears() =
testScope.runTest {
// Retrieve models to trigger caching
val model1 = underTest.viewModelForSub(1, StatusBarLocation.HOME)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
index 70d2d2b..30b95ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
@@ -105,7 +105,7 @@
}
@Test
- fun `switcher active repo - updates when demo mode changes`() =
+ fun switcherActiveRepo_updatesWhenDemoModeChanges() =
testScope.runTest {
assertThat(underTest.activeRepo.value).isSameInstanceAs(realImpl)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
index 0a3da0b..67727ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
@@ -87,7 +87,7 @@
}
@Test
- fun `Adds self to controller in constructor`() {
+ fun addsSelfToControllerInConstructor() {
val captor = kotlinArgumentCaptor<WeakReference<BaseUserSwitcherAdapter>>()
verify(controller).addAdapter(captor.capture())
@@ -100,7 +100,7 @@
}
@Test
- fun `count - ignores restricted users when device is locked`() {
+ fun count_ignoresRestrictedUsersWhenDeviceIsLocked() {
whenever(controller.isKeyguardShowing).thenReturn(true)
users =
ArrayList(
@@ -131,7 +131,7 @@
}
@Test
- fun `count - does not ignore restricted users when device is not locked`() {
+ fun count_doesNotIgnoreRestrictedUsersWhenDeviceIsNotLocked() {
whenever(controller.isKeyguardShowing).thenReturn(false)
users =
ArrayList(
@@ -185,7 +185,7 @@
}
@Test
- fun `getName - non guest - returns real name`() {
+ fun getName_nonGuest_returnsRealName() {
val userRecord =
createUserRecord(
id = 1,
@@ -196,7 +196,7 @@
}
@Test
- fun `getName - guest and selected - returns exit guest action name`() {
+ fun getName_guestAndSelected_returnsExitGuestActionName() {
val expected = "Exit guest"
context.orCreateTestableResources.addOverride(
com.android.settingslib.R.string.guest_exit_quick_settings_button,
@@ -215,7 +215,7 @@
}
@Test
- fun `getName - guest and not selected - returns enter guest action name`() {
+ fun getName_guestAndNotSelected_returnsEnterGuestActionName() {
val expected = "Guest"
context.orCreateTestableResources.addOverride(
com.android.internal.R.string.guest_name,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
index f14009aa..70eadce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/UnfoldRemoteFilterTest.kt
@@ -39,16 +39,36 @@
}
@Test
- fun onTransitionProgress_withInterval_propagated() {
- runOnMainThreadWithInterval(
- { progressProvider.onTransitionStarted() },
- { progressProvider.onTransitionProgress(0.5f) }
- )
+ fun onTransitionProgress_firstProgressEvent_propagatedImmediately() {
+ progressProvider.onTransitionStarted()
+ progressProvider.onTransitionProgress(0.5f)
listener.assertLastProgress(0.5f)
}
@Test
+ fun onTransitionProgress_secondProgressEvent_isNotPropagatedImmediately() =
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ progressProvider.onTransitionStarted()
+ progressProvider.onTransitionProgress(0.5f)
+ progressProvider.onTransitionProgress(0.8f)
+
+ // 0.8f should be set only later, after the animation
+ listener.assertLastProgress(0.5f)
+ }
+
+ @Test
+ fun onTransitionProgress_severalProgressEventsWithInterval_propagated() {
+ runOnMainThreadWithInterval(
+ { progressProvider.onTransitionStarted() },
+ { progressProvider.onTransitionProgress(0.5f) },
+ { progressProvider.onTransitionProgress(0.8f) }
+ )
+
+ listener.assertLastProgress(0.8f)
+ }
+
+ @Test
fun onTransitionEnded_propagated() {
runOnMainThreadWithInterval(
{ progressProvider.onTransitionStarted() },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
index e2f3cf7..079fbcd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
@@ -164,7 +164,7 @@
}
@Test
- fun `refreshUsers - sorts by creation time - guest user last`() = runSelfCancelingTest {
+ fun refreshUsers_sortsByCreationTime_guestUserLast() = runSelfCancelingTest {
underTest = create(this)
val unsortedUsers =
setUpUsers(
@@ -205,7 +205,7 @@
return userInfos
}
@Test
- fun `userTrackerCallback - updates selectedUserInfo`() = runSelfCancelingTest {
+ fun userTrackerCallback_updatesSelectedUserInfo() = runSelfCancelingTest {
underTest = create(this)
var selectedUserInfo: UserInfo? = null
underTest.selectedUserInfo.onEach { selectedUserInfo = it }.launchIn(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
index 0c119fd..948670f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
@@ -97,13 +97,13 @@
}
@Test
- fun `registers broadcast receivers`() {
+ fun registersBroadcastReceivers() {
verify(resumeSessionReceiver).register()
verify(resetOrExitSessionReceiver).register()
}
@Test
- fun `onDeviceBootCompleted - allowed to add - create guest`() =
+ fun onDeviceBootCompleted_allowedToAdd_createGuest() =
runBlocking(IMMEDIATE) {
setAllowedToAdd()
@@ -114,7 +114,7 @@
}
@Test
- fun `onDeviceBootCompleted - await provisioning - and create guest`() =
+ fun onDeviceBootCompleted_awaitProvisioning_andCreateGuest() =
runBlocking(IMMEDIATE) {
setAllowedToAdd(isAllowed = false)
underTest.onDeviceBootCompleted()
@@ -145,7 +145,7 @@
}
@Test
- fun `createAndSwitchTo - fails to create - does not switch to`() =
+ fun createAndSwitchTo_failsToCreate_doesNotSwitchTo() =
runBlocking(IMMEDIATE) {
whenever(manager.createGuest(any())).thenReturn(null)
@@ -162,7 +162,7 @@
}
@Test
- fun `exit - returns to target user`() =
+ fun exit_returnsToTargetUser() =
runBlocking(IMMEDIATE) {
repository.setSelectedUserInfo(GUEST_USER_INFO)
@@ -182,7 +182,7 @@
}
@Test
- fun `exit - returns to last non-guest`() =
+ fun exit_returnsToLastNonGuest() =
runBlocking(IMMEDIATE) {
val expectedUserId = NON_GUEST_USER_INFO.id
whenever(manager.getUserInfo(expectedUserId)).thenReturn(NON_GUEST_USER_INFO)
@@ -204,7 +204,7 @@
}
@Test
- fun `exit - last non-guest was removed - returns to main user`() =
+ fun exit_lastNonGuestWasRemoved_returnsToMainUser() =
runBlocking(IMMEDIATE) {
val removedUserId = 310
val mainUserId = 10
@@ -227,7 +227,7 @@
}
@Test
- fun `exit - guest was ephemeral - it is removed`() =
+ fun exit_guestWasEphemeral_itIsRemoved() =
runBlocking(IMMEDIATE) {
whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
repository.setUserInfos(listOf(NON_GUEST_USER_INFO, EPHEMERAL_GUEST_USER_INFO))
@@ -250,7 +250,7 @@
}
@Test
- fun `exit - force remove guest - it is removed`() =
+ fun exit_forceRemoveGuest_itIsRemoved() =
runBlocking(IMMEDIATE) {
whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
repository.setSelectedUserInfo(GUEST_USER_INFO)
@@ -272,7 +272,7 @@
}
@Test
- fun `exit - selected different from guest user - do nothing`() =
+ fun exit_selectedDifferentFromGuestUser_doNothing() =
runBlocking(IMMEDIATE) {
repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
@@ -289,7 +289,7 @@
}
@Test
- fun `exit - selected is actually not a guest user - do nothing`() =
+ fun exit_selectedIsActuallyNotAguestUser_doNothing() =
runBlocking(IMMEDIATE) {
repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
@@ -306,7 +306,7 @@
}
@Test
- fun `remove - returns to target user`() =
+ fun remove_returnsToTargetUser() =
runBlocking(IMMEDIATE) {
whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
repository.setSelectedUserInfo(GUEST_USER_INFO)
@@ -327,7 +327,7 @@
}
@Test
- fun `remove - selected different from guest user - do nothing`() =
+ fun remove_selectedDifferentFromGuestUser_doNothing() =
runBlocking(IMMEDIATE) {
whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
@@ -344,7 +344,7 @@
}
@Test
- fun `remove - selected is actually not a guest user - do nothing`() =
+ fun remove_selectedIsActuallyNotAguestUser_doNothing() =
runBlocking(IMMEDIATE) {
whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt
index 593ce1f..b30f77a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt
@@ -45,7 +45,7 @@
}
@Test
- fun `pause - prevents the next refresh from happening`() =
+ fun pause_preventsTheNextRefreshFromHappening() =
runBlocking(IMMEDIATE) {
underTest =
RefreshUsersScheduler(
@@ -60,7 +60,7 @@
}
@Test
- fun `unpauseAndRefresh - forces the refresh even when paused`() =
+ fun unpauseAndRefresh_forcesTheRefreshEvenWhenPaused() =
runBlocking(IMMEDIATE) {
underTest =
RefreshUsersScheduler(
@@ -76,7 +76,7 @@
}
@Test
- fun `refreshIfNotPaused - refreshes when not paused`() =
+ fun refreshIfNotPaused_refreshesWhenNotPaused() =
runBlocking(IMMEDIATE) {
underTest =
RefreshUsersScheduler(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
index adba538..d252d53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
@@ -182,7 +182,7 @@
}
@Test
- fun `testKeyguardUpdateMonitor_onKeyguardGoingAway`() =
+ fun testKeyguardUpdateMonitor_onKeyguardGoingAway() =
testScope.runTest {
val argumentCaptor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
verify(keyguardUpdateMonitor).registerCallback(argumentCaptor.capture())
@@ -194,7 +194,7 @@
}
@Test
- fun `onRecordSelected - user`() =
+ fun onRecordSelected_user() =
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -211,7 +211,7 @@
}
@Test
- fun `onRecordSelected - switch to guest user`() =
+ fun onRecordSelected_switchToGuestUser() =
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = true)
userRepository.setUserInfos(userInfos)
@@ -227,7 +227,7 @@
}
@Test
- fun `onRecordSelected - switch to restricted user`() =
+ fun onRecordSelected_switchToRestrictedUser() =
testScope.runTest {
var userInfos = createUserInfos(count = 2, includeGuest = false).toMutableList()
userInfos.add(
@@ -252,7 +252,7 @@
}
@Test
- fun `onRecordSelected - enter guest mode`() =
+ fun onRecordSelected_enterGuestMode() =
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -272,7 +272,7 @@
}
@Test
- fun `onRecordSelected - action`() =
+ fun onRecordSelected_action() =
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = true)
userRepository.setUserInfos(userInfos)
@@ -288,7 +288,7 @@
}
@Test
- fun `users - switcher enabled`() =
+ fun users_switcherEnabled() =
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = true)
userRepository.setUserInfos(userInfos)
@@ -301,7 +301,7 @@
}
@Test
- fun `users - switches to second user`() =
+ fun users_switchesToSecondUser() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -315,7 +315,7 @@
}
@Test
- fun `users - switcher not enabled`() =
+ fun users_switcherNotEnabled() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -342,7 +342,7 @@
}
@Test
- fun `actions - device unlocked`() =
+ fun actions_deviceUnlocked() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
@@ -366,7 +366,7 @@
}
@Test
- fun `actions - device unlocked - full screen`() =
+ fun actions_deviceUnlocked_fullScreen() =
testScope.runTest {
featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
val userInfos = createUserInfos(count = 2, includeGuest = false)
@@ -389,7 +389,7 @@
}
@Test
- fun `actions - device unlocked user not primary - empty list`() =
+ fun actions_deviceUnlockedUserNotPrimary_emptyList() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -402,7 +402,7 @@
}
@Test
- fun `actions - device unlocked user is guest - empty list`() =
+ fun actions_deviceUnlockedUserIsGuest_emptyList() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = true)
assertThat(userInfos[1].isGuest).isTrue()
@@ -416,7 +416,7 @@
}
@Test
- fun `actions - device locked add from lockscreen set - full list`() =
+ fun actions_deviceLockedAddFromLockscreenSet_fullList() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -442,7 +442,7 @@
}
@Test
- fun `actions - device locked add from lockscreen set - full list - full screen`() =
+ fun actions_deviceLockedAddFromLockscreenSet_fullList_fullScreen() =
testScope.runTest {
featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
val userInfos = createUserInfos(count = 2, includeGuest = false)
@@ -469,7 +469,7 @@
}
@Test
- fun `actions - device locked - only manage user is shown`() =
+ fun actions_deviceLocked_onlymanageUserIsShown() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -482,7 +482,7 @@
}
@Test
- fun `executeAction - add user - dialog shown`() =
+ fun executeAction_addUser_dialogShown() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -509,7 +509,7 @@
}
@Test
- fun `executeAction - add supervised user - dismisses dialog and starts activity`() =
+ fun executeAction_addSupervisedUser_dismissesDialogAndStartsActivity() =
testScope.runTest {
underTest.executeAction(UserActionModel.ADD_SUPERVISED_USER)
@@ -523,7 +523,7 @@
}
@Test
- fun `executeAction - navigate to manage users`() =
+ fun executeAction_navigateToManageUsers() =
testScope.runTest {
underTest.executeAction(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
@@ -533,7 +533,7 @@
}
@Test
- fun `executeAction - guest mode`() =
+ fun executeAction_guestMode() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -571,7 +571,7 @@
}
@Test
- fun `selectUser - already selected guest re-selected - exit guest dialog`() =
+ fun selectUser_alreadySelectedGuestReSelected_exitGuestDialog() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = true)
val guestUserInfo = userInfos[1]
@@ -592,7 +592,7 @@
}
@Test
- fun `selectUser - currently guest non-guest selected - exit guest dialog`() =
+ fun selectUser_currentlyGuestNonGuestSelected_exitGuestDialog() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = true)
val guestUserInfo = userInfos[1]
@@ -610,7 +610,7 @@
}
@Test
- fun `selectUser - not currently guest - switches users`() =
+ fun selectUser_notCurrentlyGuest_switchesUsers() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -626,7 +626,7 @@
}
@Test
- fun `Telephony call state changes - refreshes users`() =
+ fun telephonyCallStateChanges_refreshesUsers() =
testScope.runTest {
runCurrent()
@@ -639,7 +639,7 @@
}
@Test
- fun `User switched broadcast`() =
+ fun userSwitchedBroadcast() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -670,7 +670,7 @@
}
@Test
- fun `User info changed broadcast`() =
+ fun userInfoChangedBroadcast() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -690,7 +690,7 @@
}
@Test
- fun `System user unlocked broadcast - refresh users`() =
+ fun systemUserUnlockedBroadcast_refreshUsers() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -710,7 +710,7 @@
}
@Test
- fun `Non-system user unlocked broadcast - do not refresh users`() =
+ fun nonSystemUserUnlockedBroadcast_doNotRefreshUsers() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -799,7 +799,7 @@
}
@Test
- fun `users - secondary user - guest user can be switched to`() =
+ fun users_secondaryUser_guestUserCanBeSwitchedTo() =
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = true)
userRepository.setUserInfos(userInfos)
@@ -812,7 +812,7 @@
}
@Test
- fun `users - secondary user - no guest action`() =
+ fun users_secondaryUser_noGuestAction() =
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = true)
userRepository.setUserInfos(userInfos)
@@ -824,7 +824,7 @@
}
@Test
- fun `users - secondary user - no guest user record`() =
+ fun users_secondaryUser_noGuestUserRecord() =
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = true)
userRepository.setUserInfos(userInfos)
@@ -835,7 +835,7 @@
}
@Test
- fun `show user switcher - full screen disabled - shows dialog switcher`() =
+ fun showUserSwitcher_fullScreenDisabled_showsDialogSwitcher() =
testScope.runTest {
val expandable = mock<Expandable>()
underTest.showUserSwitcher(expandable)
@@ -851,7 +851,7 @@
}
@Test
- fun `show user switcher - full screen enabled - launches full screen dialog`() =
+ fun showUserSwitcher_fullScreenEnabled_launchesFullScreenDialog() =
testScope.runTest {
featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
@@ -869,7 +869,7 @@
}
@Test
- fun `users - secondary user - managed profile is not included`() =
+ fun users_secondaryUser_managedProfileIsNotIncluded() =
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = false).toMutableList()
userInfos.add(
@@ -889,7 +889,7 @@
}
@Test
- fun `current user is not primary and user switcher is disabled`() =
+ fun currentUserIsNotPrimaryAndUserSwitcherIsDisabled() =
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
index 9b74c1f..fd8c6c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
@@ -137,7 +137,7 @@
}
@Test
- fun `config is false - chip is disabled`() {
+ fun configIsFalse_chipIsDisabled() {
// the enabled bit is set at SystemUI startup, so recreate the view model here
userRepository.isStatusBarUserChipEnabled = false
underTest = viewModel()
@@ -146,7 +146,7 @@
}
@Test
- fun `config is true - chip is enabled`() {
+ fun configIsTrue_chipIsEnabled() {
// the enabled bit is set at SystemUI startup, so recreate the view model here
userRepository.isStatusBarUserChipEnabled = true
underTest = viewModel()
@@ -155,7 +155,7 @@
}
@Test
- fun `should show chip criteria - single user`() =
+ fun shouldShowChipCriteria_singleUser() =
testScope.runTest {
userRepository.setUserInfos(listOf(USER_0))
userRepository.setSelectedUserInfo(USER_0)
@@ -172,7 +172,7 @@
}
@Test
- fun `should show chip criteria - multiple users`() =
+ fun shouldShowChipCriteria_multipleUsers() =
testScope.runTest {
setMultipleUsers()
@@ -186,7 +186,7 @@
}
@Test
- fun `user chip name - shows selected user info`() =
+ fun userChipName_showsSelectedUserInfo() =
testScope.runTest {
setMultipleUsers()
@@ -206,7 +206,7 @@
}
@Test
- fun `user chip avatar - shows selected user info`() =
+ fun userChipAvatar_showsSelectedUserInfo() =
testScope.runTest {
setMultipleUsers()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
index a342dad..9155084 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -232,7 +232,7 @@
}
@Test
- fun `maximumUserColumns - few users`() =
+ fun maximumUserColumns_fewUsers() =
testScope.runTest {
setUsers(count = 2)
val values = mutableListOf<Int>()
@@ -244,7 +244,7 @@
}
@Test
- fun `maximumUserColumns - many users`() =
+ fun maximumUserColumns_manyUsers() =
testScope.runTest {
setUsers(count = 5)
val values = mutableListOf<Int>()
@@ -255,7 +255,7 @@
}
@Test
- fun `isOpenMenuButtonVisible - has actions - true`() =
+ fun isOpenMenuButtonVisible_hasActions_true() =
testScope.runTest {
setUsers(2)
@@ -267,7 +267,7 @@
}
@Test
- fun `isOpenMenuButtonVisible - no actions - false`() =
+ fun isOpenMenuButtonVisible_noActions_false() =
testScope.runTest {
val userInfos = setUsers(2)
userRepository.setSelectedUserInfo(userInfos[1])
@@ -298,7 +298,7 @@
}
@Test
- fun `menu actions`() =
+ fun menuActions() =
testScope.runTest {
setUsers(2)
val actions = mutableListOf<List<UserActionViewModel>>()
@@ -318,7 +318,7 @@
}
@Test
- fun `isFinishRequested - finishes when cancel button is clicked`() =
+ fun isFinishRequested_finishesWhenCancelButtonIsClicked() =
testScope.runTest {
setUsers(count = 2)
val isFinishRequested = mutableListOf<Boolean>()
@@ -338,7 +338,7 @@
}
@Test
- fun `guest selected -- name is exit guest`() =
+ fun guestSelected_nameIsExitGuest() =
testScope.runTest {
val userInfos =
listOf(
@@ -386,7 +386,7 @@
}
@Test
- fun `guest not selected -- name is guest`() =
+ fun guestNotSelected_nameIsGuest() =
testScope.runTest {
val userInfos =
listOf(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt
index 9bd3a79..3901d72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt
@@ -93,7 +93,7 @@
}
@Test
- fun `state - has wallet cards- callbacks called`() = runTest {
+ fun state_hasWalletCardsCallbacksCalled() = runTest {
setUpWalletClient(listOf(CARD_1, CARD_2, PAYMENT_CARD))
val controller = createWalletContextualSuggestionsController(backgroundScope)
var latest1 = emptyList<WalletCard>()
@@ -115,7 +115,7 @@
}
@Test
- fun `state - no wallet cards - set suggestion cards`() = runTest {
+ fun state_noWalletCards_setSuggestionCards() = runTest {
setUpWalletClient(emptyList())
val controller = createWalletContextualSuggestionsController(backgroundScope)
val latest =
@@ -132,7 +132,7 @@
}
@Test
- fun `state - has wallet cards - set and update suggestion cards`() = runTest {
+ fun state_hasWalletCards_setAndUpdateSuggestionCards() = runTest {
setUpWalletClient(listOf(CARD_1, CARD_2, PAYMENT_CARD))
val controller = createWalletContextualSuggestionsController(backgroundScope)
val latest =
@@ -151,7 +151,7 @@
}
@Test
- fun `state - wallet cards error`() = runTest {
+ fun state_walletCardsError() = runTest {
setUpWalletClient(shouldFail = true)
val controller = createWalletContextualSuggestionsController(backgroundScope)
val latest =
@@ -167,7 +167,7 @@
}
@Test
- fun `state - has wallet cards - received contextual cards - feature disabled`() = runTest {
+ fun state_hasWalletCards_receivedContextualCards_featureDisabled() = runTest {
whenever(featureFlags.isEnabled(eq(Flags.ENABLE_WALLET_CONTEXTUAL_LOYALTY_CARDS)))
.thenReturn(false)
setUpWalletClient(listOf(CARD_1, CARD_2, PAYMENT_CARD))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 9a99538..bc3a5b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -24,7 +24,6 @@
import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.wm.shell.bubbles.Bubble.KEY_APP_BUBBLE;
import static com.google.common.truth.Truth.assertThat;
@@ -1734,13 +1733,13 @@
@Test
public void testShowOrHideAppBubble_addsAndExpand() {
assertThat(mBubbleController.isStackExpanded()).isFalse();
- assertThat(mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE)).isNull();
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0, mAppBubbleIcon);
verify(mBubbleController).inflateAndAdd(any(Bubble.class), /* suppressFlyout= */ eq(true),
/* showInShade= */ eq(false));
- assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
+ assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(
+ Bubble.getAppBubbleKeyForApp(mContext.getPackageName(), mUser0));
assertThat(mBubbleController.isStackExpanded()).isTrue();
}
@@ -1754,7 +1753,8 @@
// Calling this while collapsed will expand the app bubble
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0, mAppBubbleIcon);
- assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
+ assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(
+ Bubble.getAppBubbleKeyForApp(mContext.getPackageName(), mUser0));
assertThat(mBubbleController.isStackExpanded()).isTrue();
assertThat(mBubbleData.getBubbles().size()).isEqualTo(2);
}
@@ -1762,13 +1762,15 @@
@Test
public void testShowOrHideAppBubble_collapseIfSelected() {
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0, mAppBubbleIcon);
- assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
+ assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(
+ Bubble.getAppBubbleKeyForApp(mContext.getPackageName(), mUser0));
assertThat(mBubbleController.isStackExpanded()).isTrue();
// Calling this while the app bubble is expanded should collapse the stack
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0, mAppBubbleIcon);
- assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
+ assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(
+ Bubble.getAppBubbleKeyForApp(mContext.getPackageName(), mUser0));
assertThat(mBubbleController.isStackExpanded()).isFalse();
assertThat(mBubbleData.getBubbles().size()).isEqualTo(1);
assertThat(mBubbleData.getBubbles().get(0).getUser()).isEqualTo(mUser0);
@@ -1777,8 +1779,9 @@
@Test
public void testShowOrHideAppBubbleWithNonPrimaryUser_bubbleCollapsedWithExpectedUser() {
UserHandle user10 = createUserHandle(/* userId = */ 10);
+ String appBubbleKey = Bubble.getAppBubbleKeyForApp(mContext.getPackageName(), user10);
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, user10, mAppBubbleIcon);
- assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
+ assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(appBubbleKey);
assertThat(mBubbleController.isStackExpanded()).isTrue();
assertThat(mBubbleData.getBubbles().size()).isEqualTo(1);
assertThat(mBubbleData.getBubbles().get(0).getUser()).isEqualTo(user10);
@@ -1786,13 +1789,28 @@
// Calling this while the app bubble is expanded should collapse the stack
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, user10, mAppBubbleIcon);
- assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
+ assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(appBubbleKey);
assertThat(mBubbleController.isStackExpanded()).isFalse();
assertThat(mBubbleData.getBubbles().size()).isEqualTo(1);
assertThat(mBubbleData.getBubbles().get(0).getUser()).isEqualTo(user10);
}
@Test
+ public void testShowOrHideAppBubbleOnUser10AndThenUser0_user0BubbleExpanded() {
+ UserHandle user10 = createUserHandle(/* userId = */ 10);
+ mBubbleController.showOrHideAppBubble(mAppBubbleIntent, user10, mAppBubbleIcon);
+
+ String appBubbleUser0Key = Bubble.getAppBubbleKeyForApp(mContext.getPackageName(), mUser0);
+ mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0, mAppBubbleIcon);
+
+ assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(appBubbleUser0Key);
+ assertThat(mBubbleController.isStackExpanded()).isTrue();
+ assertThat(mBubbleData.getBubbles()).hasSize(2);
+ assertThat(mBubbleData.getBubbles().get(0).getUser()).isEqualTo(mUser0);
+ assertThat(mBubbleData.getBubbles().get(1).getUser()).isEqualTo(user10);
+ }
+
+ @Test
public void testShowOrHideAppBubble_selectIfNotSelected() {
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0, mAppBubbleIcon);
mBubbleController.updateBubble(mBubbleEntry);
@@ -1801,7 +1819,8 @@
assertThat(mBubbleController.isStackExpanded()).isTrue();
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0, mAppBubbleIcon);
- assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
+ assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(
+ Bubble.getAppBubbleKeyForApp(mContext.getPackageName(), mUser0));
assertThat(mBubbleController.isStackExpanded()).isTrue();
assertThat(mBubbleData.getBubbles().size()).isEqualTo(2);
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt
index 3041888..843cc3b 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldRemoteFilter.kt
@@ -34,6 +34,7 @@
}
private var inProgress = false
+ private var receivedProgressEvent = false
private var processedProgress: Float = 1.0f
set(newProgress) {
@@ -54,7 +55,16 @@
override fun onTransitionProgress(progress: Float) {
logCounter({ "$TAG#plain_remote_progress" }, progress)
if (inProgress) {
- springAnimation.animateToFinalPosition(progress)
+ if (receivedProgressEvent) {
+ // We have received at least one progress event, animate from the previous
+ // progress to the current
+ springAnimation.animateToFinalPosition(progress)
+ } else {
+ // This is the first progress event after starting the animation, send it
+ // straightaway and set the spring value without animating it
+ processedProgress = progress
+ receivedProgressEvent = true
+ }
} else {
Log.e(TAG, "Progress received while not in progress.")
}
@@ -62,6 +72,7 @@
override fun onTransitionFinished() {
inProgress = false
+ receivedProgressEvent = false
listener.onTransitionFinished()
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 22e742b..c1c47f5 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -231,6 +231,12 @@
*/
public void transitionMagnificationModeLocked(int displayId, int targetMode,
@NonNull TransitionCallBack transitionCallBack) {
+ // check if target mode is already activated
+ if (isActivated(displayId, targetMode)) {
+ transitionCallBack.onResult(displayId, true);
+ return;
+ }
+
final PointF currentCenter = getCurrentMagnificationCenterLocked(displayId, targetMode);
final DisableMagnificationCallback animationCallback =
getDisableMagnificationEndRunnableLocked(displayId);
@@ -322,13 +328,16 @@
: config.getScale();
try {
setTransitionState(displayId, targetMode);
+ final MagnificationAnimationCallback magnificationAnimationCallback = animate
+ ? success -> mAms.changeMagnificationMode(displayId, targetMode)
+ : null;
// Activate or deactivate target mode depending on config activated value
if (targetMode == MAGNIFICATION_MODE_WINDOW) {
screenMagnificationController.reset(displayId, false);
if (targetActivated) {
windowMagnificationMgr.enableWindowMagnification(displayId,
targetScale, magnificationCenter.x, magnificationCenter.y,
- animate ? STUB_ANIMATION_CALLBACK : null, id);
+ magnificationAnimationCallback, id);
} else {
windowMagnificationMgr.disableWindowMagnification(displayId, false);
}
@@ -339,8 +348,8 @@
screenMagnificationController.register(displayId);
}
screenMagnificationController.setScaleAndCenter(displayId, targetScale,
- magnificationCenter.x, magnificationCenter.y, animate,
- id);
+ magnificationCenter.x, magnificationCenter.y,
+ magnificationAnimationCallback, id);
} else {
if (screenMagnificationController.isRegistered(displayId)) {
screenMagnificationController.reset(displayId, false);
@@ -348,6 +357,9 @@
}
}
} finally {
+ if (!animate) {
+ mAms.changeMagnificationMode(displayId, targetMode);
+ }
// Reset transition state after enabling target mode.
setTransitionState(displayId, null);
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 2a964b8..3bd4547 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -56,6 +56,10 @@
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;
import static com.android.server.autofill.Helper.toArray;
+import static com.android.server.autofill.PresentationStatsEventLogger.AUTHENTICATION_RESULT_FAILURE;
+import static com.android.server.autofill.PresentationStatsEventLogger.AUTHENTICATION_RESULT_SUCCESS;
+import static com.android.server.autofill.PresentationStatsEventLogger.AUTHENTICATION_TYPE_DATASET_AUTHENTICATION;
+import static com.android.server.autofill.PresentationStatsEventLogger.AUTHENTICATION_TYPE_FULL_AUTHENTICATION;
import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_NO_FOCUS;
import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_REQUEST_FAILED;
import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_REQUEST_TIMEOUT;
@@ -75,6 +79,12 @@
import static com.android.server.autofill.SaveEventLogger.SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE;
import static com.android.server.autofill.SaveEventLogger.SAVE_UI_SHOWN_REASON_TRIGGER_ID_SET;
import static com.android.server.autofill.SaveEventLogger.SAVE_UI_SHOWN_REASON_UNKNOWN;
+import static com.android.server.autofill.SessionCommittedEventLogger.CommitReason;
+import static com.android.server.autofill.SessionCommittedEventLogger.COMMIT_REASON_ACTIVITY_FINISHED;
+import static com.android.server.autofill.SessionCommittedEventLogger.COMMIT_REASON_VIEW_CHANGED;
+import static com.android.server.autofill.SessionCommittedEventLogger.COMMIT_REASON_VIEW_CLICKED;
+import static com.android.server.autofill.SessionCommittedEventLogger.COMMIT_REASON_VIEW_COMMITTED;
+import static com.android.server.autofill.SessionCommittedEventLogger.COMMIT_REASON_SESSION_DESTROYED;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
@@ -364,6 +374,11 @@
private final long mStartTime;
/**
+ * Count of FillRequests in the session.
+ */
+ private int mRequestCount;
+
+ /**
* Starting timestamp of latency logger.
* This is set when Session created or when the view is reset.
*/
@@ -1132,6 +1147,7 @@
int flags) {
final FillResponse existingResponse = viewState.getResponse();
mFillRequestEventLogger.startLogForNewRequest();
+ mRequestCount++;
mFillRequestEventLogger.maybeSetAppPackageUid(uid);
mFillRequestEventLogger.maybeSetFlags(mFlags);
if(mPreviouslyFillDialogPotentiallyStarted) {
@@ -1330,8 +1346,6 @@
this.userId = userId;
this.taskId = taskId;
this.uid = uid;
- mStartTime = SystemClock.elapsedRealtime();
- mLatencyBaseTime = mStartTime;
mService = service;
mLock = lock;
mUi = ui;
@@ -1347,11 +1361,17 @@
mComponentName = componentName;
mCompatMode = compatMode;
mSessionState = STATE_ACTIVE;
+ // Initiate all loggers & counters.
+ mStartTime = SystemClock.elapsedRealtime();
+ mLatencyBaseTime = mStartTime;
+ mRequestCount = 0;
mPresentationStatsEventLogger = PresentationStatsEventLogger.forSessionId(sessionId);
mFillRequestEventLogger = FillRequestEventLogger.forSessionId(sessionId);
mFillResponseEventLogger = FillResponseEventLogger.forSessionId(sessionId);
mSessionCommittedEventLogger = SessionCommittedEventLogger.forSessionId(sessionId);
+ mSessionCommittedEventLogger.maybeSetComponentPackageUid(uid);
mSaveEventLogger = SaveEventLogger.forSessionId(sessionId);
+
synchronized (mLock) {
mSessionFlags = new SessionFlags();
mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly;
@@ -1971,6 +1991,7 @@
// Start a new FillRequest logger for client suggestion fallback.
mFillRequestEventLogger.startLogForNewRequest();
+ mRequestCount++;
mFillRequestEventLogger.maybeSetAppPackageUid(uid);
mFillRequestEventLogger.maybeSetFlags(
flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS);
@@ -2187,6 +2208,8 @@
}
final Intent fillInIntent;
synchronized (mLock) {
+ mPresentationStatsEventLogger.maybeSetAuthenticationType(
+ AUTHENTICATION_TYPE_FULL_AUTHENTICATION);
if (mDestroyed) {
Slog.w(TAG, "Call to Session#authenticate() rejected - session: "
+ id + " destroyed");
@@ -2231,7 +2254,6 @@
if (mDestroyed) {
Slog.w(TAG, "Call to Session#save() rejected - session: "
+ id + " destroyed");
- mSaveEventLogger.logAndEndEvent();
return;
}
}
@@ -2251,7 +2273,6 @@
if (mDestroyed) {
Slog.w(TAG, "Call to Session#cancelSave() rejected - session: "
+ id + " destroyed");
- mSaveEventLogger.logAndEndEvent();
return;
}
}
@@ -2438,18 +2459,26 @@
final int requestId = AutofillManager.getRequestIdFromAuthenticationId(authenticationId);
if (requestId == AUGMENTED_AUTOFILL_REQUEST_ID) {
setAuthenticationResultForAugmentedAutofillLocked(data, authenticationId);
+ // Augmented autofill is not logged.
+ mPresentationStatsEventLogger.logAndEndEvent();
return;
}
if (mResponses == null) {
// Typically happens when app explicitly called cancel() while the service was showing
// the auth UI.
Slog.w(TAG, "setAuthenticationResultLocked(" + authenticationId + "): no responses");
+ mPresentationStatsEventLogger.maybeSetAuthenticationResult(
+ AUTHENTICATION_RESULT_FAILURE);
+ mPresentationStatsEventLogger.logAndEndEvent();
removeFromService();
return;
}
final FillResponse authenticatedResponse = mResponses.get(requestId);
if (authenticatedResponse == null || data == null) {
Slog.w(TAG, "no authenticated response");
+ mPresentationStatsEventLogger.maybeSetAuthenticationResult(
+ AUTHENTICATION_RESULT_FAILURE);
+ mPresentationStatsEventLogger.logAndEndEvent();
removeFromService();
return;
}
@@ -2461,6 +2490,9 @@
final Dataset dataset = authenticatedResponse.getDatasets().get(datasetIdx);
if (dataset == null) {
Slog.w(TAG, "no dataset with index " + datasetIdx + " on fill response");
+ mPresentationStatsEventLogger.maybeSetAuthenticationResult(
+ AUTHENTICATION_RESULT_FAILURE);
+ mPresentationStatsEventLogger.logAndEndEvent();
removeFromService();
return;
}
@@ -2477,11 +2509,15 @@
}
if (result instanceof FillResponse) {
logAuthenticationStatusLocked(requestId, MetricsEvent.AUTOFILL_AUTHENTICATED);
+ mPresentationStatsEventLogger.maybeSetAuthenticationResult(
+ AUTHENTICATION_RESULT_SUCCESS);
replaceResponseLocked(authenticatedResponse, (FillResponse) result, newClientState);
} else if (result instanceof Dataset) {
if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) {
logAuthenticationStatusLocked(requestId,
MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED);
+ mPresentationStatsEventLogger.maybeSetAuthenticationResult(
+ AUTHENTICATION_RESULT_SUCCESS);
if (newClientState != null) {
if (sDebug) Slog.d(TAG, "Updating client state from auth dataset");
mClientState = newClientState;
@@ -2497,6 +2533,8 @@
+ authenticationId);
logAuthenticationStatusLocked(requestId,
MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION);
+ mPresentationStatsEventLogger.maybeSetAuthenticationResult(
+ AUTHENTICATION_RESULT_FAILURE);
}
} else {
if (result != null) {
@@ -2504,6 +2542,8 @@
}
logAuthenticationStatusLocked(requestId,
MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION);
+ mPresentationStatsEventLogger.maybeSetAuthenticationResult(
+ AUTHENTICATION_RESULT_FAILURE);
processNullResponseLocked(requestId, 0);
}
}
@@ -4790,6 +4830,7 @@
}
// Log FillRequest for Augmented Autofill.
mFillRequestEventLogger.startLogForNewRequest();
+ mRequestCount++;
mFillRequestEventLogger.maybeSetAppPackageUid(uid);
mFillRequestEventLogger.maybeSetFlags(mFlags);
mFillRequestEventLogger.maybeSetRequestId(AUGMENTED_AUTOFILL_REQUEST_ID);
@@ -5036,6 +5077,7 @@
if (dataset.getAuthentication() == null) {
if (generateEvent) {
mService.logDatasetSelected(dataset.getId(), id, mClientState, uiType);
+ mPresentationStatsEventLogger.maybeSetSelectedDatasetId(datasetIndex);
}
if (mCurrentViewId != null) {
mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
@@ -5046,6 +5088,8 @@
// ...or handle authentication.
mService.logDatasetAuthenticationSelected(dataset.getId(), id, mClientState, uiType);
+ mPresentationStatsEventLogger.maybeSetAuthenticationType(
+ AUTHENTICATION_TYPE_DATASET_AUTHENTICATION);
setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false);
final Intent fillInIntent = createAuthFillInIntentLocked(requestId, mClientState);
if (fillInIntent == null) {
@@ -5639,6 +5683,17 @@
*/
@GuardedBy("mLock")
RemoteFillService destroyLocked() {
+ // Log unlogged events.
+ mSessionCommittedEventLogger.maybeSetCommitReason(COMMIT_REASON_SESSION_DESTROYED);
+ mSessionCommittedEventLogger.maybeSetRequestCount(mRequestCount);
+ mSessionCommittedEventLogger.maybeSetSessionDurationMillis(
+ SystemClock.elapsedRealtime() - mStartTime);
+ mSessionCommittedEventLogger.logAndEndEvent();
+ mPresentationStatsEventLogger.logAndEndEvent();
+ mSaveEventLogger.logAndEndEvent();
+ mFillResponseEventLogger.logAndEndEvent();
+ mFillRequestEventLogger.logAndEndEvent();
+
if (mDestroyed) {
return null;
}
diff --git a/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java b/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java
index 92d72ac..541ec80 100644
--- a/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java
@@ -18,6 +18,7 @@
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_ACTIVITY_FINISHED;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_SESSION_DESTROYED;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_VIEW_CHANGED;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_VIEW_CLICKED;
@@ -53,7 +54,8 @@
COMMIT_REASON_ACTIVITY_FINISHED,
COMMIT_REASON_VIEW_COMMITTED,
COMMIT_REASON_VIEW_CLICKED,
- COMMIT_REASON_VIEW_CHANGED
+ COMMIT_REASON_VIEW_CHANGED,
+ COMMIT_REASON_SESSION_DESTROYED
})
@Retention(RetentionPolicy.SOURCE)
public @interface CommitReason {
@@ -69,6 +71,8 @@
AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_VIEW_CLICKED;
public static final int COMMIT_REASON_VIEW_CHANGED =
AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_VIEW_CHANGED;
+ public static final int COMMIT_REASON_SESSION_DESTROYED =
+ AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_SESSION_DESTROYED;
private final int mSessionId;
private Optional<SessionCommittedEventInternal> mEventInternal;
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index b042c30..ff72476 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -397,7 +397,7 @@
setUpPipes();
mAgent = mBackupManagerService.bindToAgentSynchronous(mTargetApp,
FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain)
- ? ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL
+ ? ApplicationThreadConstants.BACKUP_MODE_RESTORE
: ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL,
mBackupEligibilityRules.getBackupDestination());
mAgentPackage = pkg;
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 1656b6f..77990af 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -677,7 +677,7 @@
// Good to go! Set up and bind the agent...
mAgent = backupManagerService.bindToAgentSynchronous(
mCurrentPackage.applicationInfo,
- ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL,
+ ApplicationThreadConstants.BACKUP_MODE_RESTORE,
mBackupEligibilityRules.getBackupDestination());
if (mAgent == null) {
Slog.w(TAG, "Can't find backup agent for " + packageName);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 6adccf6..df3c95b 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -829,7 +829,8 @@
// Service.startForeground()), at that point we will consult the BFSL check and the timeout
// and make the necessary decisions.
setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, r, userId,
- backgroundStartPrivileges, false /* isBindService */);
+ backgroundStartPrivileges, false /* isBindService */,
+ !fgRequired /* isStartService */);
if (!mAm.mUserController.exists(r.userId)) {
Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
@@ -2119,7 +2120,11 @@
}
}
- if (r.isForeground && isOldTypeShortFgs) {
+ final boolean enableFgsWhileInUseFix = mAm.mConstants.mEnableFgsWhileInUseFix;
+ final boolean fgsTypeChangingFromShortFgs = r.isForeground && isOldTypeShortFgs;
+
+ if (fgsTypeChangingFromShortFgs) {
+
// If we get here, that means startForeground(SHORT_SERVICE) is called again
// on a SHORT_SERVICE FGS.
@@ -2128,7 +2133,7 @@
setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
r.appInfo.uid, r.intent.getIntent(), r, r.userId,
BackgroundStartPrivileges.NONE,
- false /* isBindService */);
+ false /* isBindService */, false /* isStartService */);
if (r.mAllowStartForeground == REASON_DENIED) {
Slog.w(TAG_SERVICE, "FGS type change to/from SHORT_SERVICE: "
+ " BFSL DENIED.");
@@ -2171,8 +2176,19 @@
// "if (r.mAllowStartForeground == REASON_DENIED...)" block below.
}
}
+ }
- } else if (r.mStartForegroundCount == 0) {
+ // Re-evaluate mAllowWhileInUsePermissionInFgs and mAllowStartForeground
+ // (i.e. while-in-use and BFSL flags) if needed.
+ //
+ // Consider the below if-else section to be in the else of the above
+ // `if (fgsTypeChangingFromShortFgs)`.
+ // Using an else would increase the indent further, so we don't use it here
+ // and instead just add !fgsTypeChangingFromShortFgs to all if's.
+ //
+ // The first if's are for the original while-in-use logic.
+ if (!fgsTypeChangingFromShortFgs && !enableFgsWhileInUseFix
+ && r.mStartForegroundCount == 0) {
/*
If the service was started with startService(), not
startForegroundService(), and if startForeground() isn't called within
@@ -2193,7 +2209,7 @@
setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
r.appInfo.uid, r.intent.getIntent(), r, r.userId,
BackgroundStartPrivileges.NONE,
- false /* isBindService */);
+ false /* isBindService */, false /* isStartService */);
final String temp = "startForegroundDelayMs:" + delayMs;
if (r.mInfoAllowStartForeground != null) {
r.mInfoAllowStartForeground += "; " + temp;
@@ -2203,9 +2219,10 @@
r.mLoggedInfoAllowStartForeground = false;
}
}
- } else if (r.mStartForegroundCount >= 1) {
+ } else if (!fgsTypeChangingFromShortFgs && !enableFgsWhileInUseFix
+ && r.mStartForegroundCount >= 1) {
// We get here if startForeground() is called multiple times
- // on the same sarvice after it's created, regardless of whether
+ // on the same service after it's created, regardless of whether
// stopForeground() has been called or not.
// The second or later time startForeground() is called after service is
@@ -2213,7 +2230,71 @@
setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
r.appInfo.uid, r.intent.getIntent(), r, r.userId,
BackgroundStartPrivileges.NONE,
- false /* isBindService */);
+ false /* isBindService */, false /* isStartService */);
+ } else if (!fgsTypeChangingFromShortFgs && enableFgsWhileInUseFix) {
+ // The new while-in-use logic.
+ //
+ // When startForeground() is called, we _always_ call
+ // setFgsRestrictionLocked() to set the restrictions according to the
+ // current state of the app.
+ // (So if the app is now in TOP, for example, the service will now always
+ // get while-in-use permissions.)
+ //
+ // Note, setFgsRestrictionLocked() will never disallow
+ // mAllowWhileInUsePermissionInFgs nor mAllowStartForeground
+ // (i.e. while-in-use and BFSL flags) once they're set to "allowed".
+ //
+ // HOWEVER, if these flags were set to "allowed" in Context.startService()
+ // (as opposed to startForegroundService()), when the service wasn't yet
+ // a foreground service, then we may not always
+ // want to trust them -- for example, if the service has been running as a
+ // BG service or a bound service for a long time when the app is not longer
+ // in the foreground, then we shouldn't grant while-in-user nor BFSL.
+ // So in that case, we need to reset it first.
+
+ final long delayMs =
+ (r.mLastUntrustedSetFgsRestrictionAllowedTime == 0) ? 0
+ : (SystemClock.elapsedRealtime()
+ - r.mLastUntrustedSetFgsRestrictionAllowedTime);
+ final boolean resetNeeded =
+ !r.isForeground
+ && delayMs > mAm.mConstants.mFgsStartForegroundTimeoutMs;
+ if (resetNeeded) {
+ resetFgsRestrictionLocked(r);
+ }
+ setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
+ r.appInfo.uid, r.intent.getIntent(), r, r.userId,
+ BackgroundStartPrivileges.NONE,
+ false /* isBindService */, false /* isStartService */);
+
+ final String temp = "startForegroundDelayMs:" + delayMs
+ + "; started: " + r.startRequested
+ + "; num_bindings: " + r.getConnections().size()
+ + "; wasForeground: " + r.isForeground
+ + "; resetNeeded:" + resetNeeded;
+ if (r.mInfoAllowStartForeground != null) {
+ r.mInfoAllowStartForeground += "; " + temp;
+ } else {
+ r.mInfoAllowStartForeground = temp;
+ }
+ r.mLoggedInfoAllowStartForeground = false;
+ }
+
+ // If the service has any bindings and it's not yet a FGS
+ // we compare the new and old while-in-use logics.
+ // (If it's not the first startForeground() call, we already reset the
+ // while-in-use and BFSL flags, so the logic change wouldn't matter.)
+ if (enableFgsWhileInUseFix
+ && !r.isForeground
+ && (r.getConnections().size() > 0)
+ && (r.mDebugWhileInUseReasonInBindService
+ != r.mDebugWhileInUseReasonInStartForeground)) {
+ Slog.wtf(TAG, "FGS while-in-use changed (b/276963716): old="
+ + reasonCodeToString(r.mDebugWhileInUseReasonInBindService)
+ + " new="
+ + reasonCodeToString(r.mDebugWhileInUseReasonInStartForeground)
+ + " "
+ + r.shortInstanceName);
}
// If the foreground service is not started from TOP process, do not allow it to
@@ -2321,6 +2402,11 @@
active.mNumActive++;
}
r.isForeground = true;
+
+ // Once the service becomes a foreground service,
+ // the FGS restriction information always becomes "trustable".
+ r.mLastUntrustedSetFgsRestrictionAllowedTime = 0;
+
// The logging of FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER event could
// be deferred, make a copy of mAllowStartForeground and
// mAllowWhileInUsePermissionInFgs.
@@ -3663,8 +3749,25 @@
return 0;
}
}
- setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, userId,
- BackgroundStartPrivileges.NONE, true /* isBindService */);
+ if (!mAm.mConstants.mEnableFgsWhileInUseFix) {
+ // Old while-in-use logic.
+ setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, userId,
+ BackgroundStartPrivileges.NONE, true /* isBindService */,
+ false /* isStartService */);
+ } else {
+ // New logic will not call setFgsRestrictionLocked() here, but we still
+ // keep track of the allow reason from the old logic here, so we can compare to
+ // the new logic.
+ // Once we're confident enough in the new logic, we should remove it.
+ if (s.mDebugWhileInUseReasonInBindService == REASON_DENIED) {
+ s.mDebugWhileInUseReasonInBindService =
+ shouldAllowFgsWhileInUsePermissionLocked(
+ callingPackage, callingPid, callingUid, s.app,
+ BackgroundStartPrivileges.NONE,
+ true /* isBindService */,
+ false /* DO NOT enableFgsWhileInUseFix; use the old logic */);
+ }
+ }
if (s.app != null) {
ProcessServiceRecord servicePsr = s.app.mServices;
@@ -7357,45 +7460,76 @@
* @param callingUid caller app's uid.
* @param intent intent to start/bind service.
* @param r the service to start.
+ * @param isStartService True if it's called from Context.startService().
+ * False if it's called from Context.startForegroundService() or
+ * Service.startService().
* @return true if allow, false otherwise.
*/
private void setFgsRestrictionLocked(String callingPackage,
int callingPid, int callingUid, Intent intent, ServiceRecord r, int userId,
- BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) {
- r.mLastSetFgsRestrictionTime = SystemClock.elapsedRealtime();
+ BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService,
+ boolean isStartService) {
+ final long now = SystemClock.elapsedRealtime();
+
// Check DeviceConfig flag.
if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) {
r.mAllowWhileInUsePermissionInFgs = true;
}
final @ReasonCode int allowWhileInUse;
+
+ // Either (or both) mAllowWhileInUsePermissionInFgs or mAllowStartForeground is
+ // newly allowed?
+ boolean newlyAllowed = false;
if (!r.mAllowWhileInUsePermissionInFgs
|| (r.mAllowStartForeground == REASON_DENIED)) {
allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
callingPackage, callingPid, callingUid, r.app, backgroundStartPrivileges,
isBindService);
+ // We store them to compare the old and new while-in-use logics to each other.
+ // (They're not used for any other purposes.)
+ if (isBindService) {
+ r.mDebugWhileInUseReasonInBindService = allowWhileInUse;
+ } else {
+ r.mDebugWhileInUseReasonInStartForeground = allowWhileInUse;
+ }
if (!r.mAllowWhileInUsePermissionInFgs) {
r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != REASON_DENIED);
+ newlyAllowed |= r.mAllowWhileInUsePermissionInFgs;
}
if (r.mAllowStartForeground == REASON_DENIED) {
r.mAllowStartForeground = shouldAllowFgsStartForegroundWithBindingCheckLocked(
allowWhileInUse, callingPackage, callingPid, callingUid, intent, r,
backgroundStartPrivileges, isBindService);
+ newlyAllowed |= r.mAllowStartForeground != REASON_DENIED;
}
} else {
allowWhileInUse = REASON_UNKNOWN;
}
r.mAllowWhileInUsePermissionInFgsReason = allowWhileInUse;
+
+ if (isStartService && !r.isForeground && newlyAllowed) {
+ // If it's called by Context.startService() (not by startForegroundService()),
+ // and we're setting "allowed", then we can't fully trust it yet -- we'll need to reset
+ // the restrictions if startForeground() is called after the grace period.
+ r.mLastUntrustedSetFgsRestrictionAllowedTime = now;
+ }
}
void resetFgsRestrictionLocked(ServiceRecord r) {
r.mAllowWhileInUsePermissionInFgs = false;
r.mAllowWhileInUsePermissionInFgsReason = REASON_DENIED;
+ r.mDebugWhileInUseReasonInStartForeground = REASON_DENIED;
+ // We don't reset mWhileInUseReasonInBindService here, because if we do this, we would
+ // lose it in the "reevaluation" case in startForeground(), where we call
+ // resetFgsRestrictionLocked().
+ // Not resetting this is fine because it's only used in the first Service.startForeground()
+ // case, and there's no situations where we call resetFgsRestrictionLocked() before that.
r.mAllowStartForeground = REASON_DENIED;
r.mInfoAllowStartForeground = null;
r.mInfoTempFgsAllowListReason = null;
r.mLoggedInfoAllowStartForeground = false;
- r.mLastSetFgsRestrictionTime = 0;
+ r.mLastUntrustedSetFgsRestrictionAllowedTime = 0;
r.updateAllowUiJobScheduling(r.mAllowWhileInUsePermissionInFgs);
}
@@ -7430,14 +7564,29 @@
private @ReasonCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage,
int callingPid, int callingUid, @Nullable ProcessRecord targetProcess,
BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) {
+ return shouldAllowFgsWhileInUsePermissionLocked(callingPackage,
+ callingPid, callingUid, targetProcess, backgroundStartPrivileges, isBindService,
+ /* enableFgsWhileInUseFix =*/ mAm.mConstants.mEnableFgsWhileInUseFix);
+ }
+
+ private @ReasonCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage,
+ int callingPid, int callingUid, @Nullable ProcessRecord targetProcess,
+ BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService,
+ boolean enableFgsWhileInUseFix) {
int ret = REASON_DENIED;
- final int uidState = mAm.getUidStateLocked(callingUid);
- if (ret == REASON_DENIED) {
- // Allow FGS while-in-use if the caller's process state is PROCESS_STATE_PERSISTENT,
- // PROCESS_STATE_PERSISTENT_UI or PROCESS_STATE_TOP.
- if (uidState <= PROCESS_STATE_TOP) {
- ret = getReasonCodeFromProcState(uidState);
+ // Define some local variables for better readability...
+ final boolean useOldLogic = !enableFgsWhileInUseFix;
+ final boolean forStartForeground = !isBindService;
+
+ if (useOldLogic || forStartForeground) {
+ final int uidState = mAm.getUidStateLocked(callingUid);
+ if (ret == REASON_DENIED) {
+ // Allow FGS while-in-use if the caller's process state is PROCESS_STATE_PERSISTENT,
+ // PROCESS_STATE_PERSISTENT_UI or PROCESS_STATE_TOP.
+ if (uidState <= PROCESS_STATE_TOP) {
+ ret = getReasonCodeFromProcState(uidState);
+ }
}
}
@@ -7480,6 +7629,10 @@
}
}
+ if (enableFgsWhileInUseFix && ret == REASON_DENIED) {
+ ret = shouldAllowFgsWhileInUsePermissionByBindingsLocked(callingUid);
+ }
+
if (ret == REASON_DENIED) {
// Allow FGS while-in-use if the WindowManager allows background activity start.
// This is mainly to get the 10 seconds grace period if any activity in the caller has
@@ -7558,6 +7711,59 @@
}
/**
+ * Check all bindings into the calling UID, and see if:
+ * - It's bound by a TOP app
+ * - or, bound by a persistent process with BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS.
+ */
+ private @ReasonCode int shouldAllowFgsWhileInUsePermissionByBindingsLocked(int callingUid) {
+ final ArraySet<Integer> checkedClientUids = new ArraySet<>();
+ final Integer result = mAm.mProcessList.searchEachLruProcessesLOSP(
+ false, pr -> {
+ if (pr.uid != callingUid) {
+ return null;
+ }
+ final ProcessServiceRecord psr = pr.mServices;
+ final int serviceCount = psr.mServices.size();
+ for (int svc = 0; svc < serviceCount; svc++) {
+ final ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns =
+ psr.mServices.valueAt(svc).getConnections();
+ final int size = conns.size();
+ for (int conni = 0; conni < size; conni++) {
+ final ArrayList<ConnectionRecord> crs = conns.valueAt(conni);
+ for (int con = 0; con < crs.size(); con++) {
+ final ConnectionRecord cr = crs.get(con);
+ final ProcessRecord clientPr = cr.binding.client;
+ final int clientUid = clientPr.uid;
+
+ // An UID can bind to itself, do not check on itself again.
+ // Also skip already checked clientUid.
+ if (clientUid == callingUid
+ || checkedClientUids.contains(clientUid)) {
+ continue;
+ }
+
+ // Binding found, check the client procstate and the flag.
+ final int clientUidState = mAm.getUidStateLocked(callingUid);
+ final boolean boundByTop = clientUidState == PROCESS_STATE_TOP;
+ final boolean boundByPersistentWithBal =
+ clientUidState < PROCESS_STATE_TOP
+ && cr.hasFlag(
+ Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS);
+ if (boundByTop || boundByPersistentWithBal) {
+ return getReasonCodeFromProcState(clientUidState);
+ }
+
+ // Don't check the same UID.
+ checkedClientUids.add(clientUid);
+ }
+ }
+ }
+ return null;
+ });
+ return result == null ? REASON_DENIED : result;
+ }
+
+ /**
* The uid is not allowed to start FGS, but the uid has a service that is bound
* by a clientUid, if the clientUid can start FGS, then the clientUid can propagate its
* BG-FGS-start capability down to the callingUid.
@@ -8142,7 +8348,8 @@
r.mFgsEnterTime = SystemClock.uptimeMillis();
r.foregroundServiceType = options.mForegroundServiceTypes;
setFgsRestrictionLocked(callingPackage, callingPid, callingUid, intent, r, userId,
- BackgroundStartPrivileges.NONE, false);
+ BackgroundStartPrivileges.NONE, false /* isBindService */,
+ false /* isStartService */);
final ProcessServiceRecord psr = callerApp.mServices;
final boolean newService = psr.startService(r);
// updateOomAdj.
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 44e198b..3841b6a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -1058,6 +1058,13 @@
/** @see #KEY_USE_MODERN_TRIM */
public boolean USE_MODERN_TRIM = DEFAULT_USE_MODERN_TRIM;
+ private static final String KEY_ENABLE_FGS_WHILE_IN_USE_FIX =
+ "key_enable_fgs_while_in_use_fix";
+
+ private static final boolean DEFAULT_ENABLE_FGS_WHILE_IN_USE_FIX = true;
+
+ public volatile boolean mEnableFgsWhileInUseFix = DEFAULT_ENABLE_FGS_WHILE_IN_USE_FIX;
+
private final OnPropertiesChangedListener mOnDeviceConfigChangedListener =
new OnPropertiesChangedListener() {
@Override
@@ -1226,6 +1233,9 @@
case KEY_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION:
updateEnableWaitForFinishAttachApplication();
break;
+ case KEY_ENABLE_FGS_WHILE_IN_USE_FIX:
+ updateEnableFgsWhileInUseFix();
+ break;
case KEY_MAX_PREVIOUS_TIME:
updateMaxPreviousTime();
break;
@@ -1995,6 +2005,12 @@
DEFAULT_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION);
}
+ private void updateEnableFgsWhileInUseFix() {
+ mEnableFgsWhileInUseFix = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_ENABLE_FGS_WHILE_IN_USE_FIX,
+ DEFAULT_ENABLE_FGS_WHILE_IN_USE_FIX);
+ }
private void updateUseTieredCachedAdj() {
USE_TIERED_CACHED_ADJ = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -2195,6 +2211,9 @@
pw.print(" "); pw.print(KEY_SYSTEM_EXEMPT_POWER_RESTRICTIONS_ENABLED);
pw.print("="); pw.println(mFlagSystemExemptPowerRestrictionsEnabled);
+ pw.print(" "); pw.print(KEY_ENABLE_FGS_WHILE_IN_USE_FIX);
+ pw.print("="); pw.println(mEnableFgsWhileInUseFix);
+
pw.print(" "); pw.print(KEY_SHORT_FGS_TIMEOUT_DURATION);
pw.print("="); pw.println(mShortFgsTimeoutDuration);
pw.print(" "); pw.print(KEY_SHORT_FGS_PROC_STATE_EXTRA_WAIT_DURATION);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 97d34b8..1f80aec 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -382,6 +382,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import android.util.StatsEvent;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoUtils;
@@ -1595,6 +1596,7 @@
static final int SERVICE_SHORT_FGS_TIMEOUT_MSG = 76;
static final int SERVICE_SHORT_FGS_PROCSTATE_TIMEOUT_MSG = 77;
static final int SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG = 78;
+ static final int UPDATE_CACHED_APP_HIGH_WATERMARK = 79;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1938,6 +1940,9 @@
case SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG: {
mServices.onShortFgsAnrTimeout((ServiceRecord) msg.obj);
} break;
+ case UPDATE_CACHED_APP_HIGH_WATERMARK: {
+ mAppProfiler.mCachedAppsWatermarkData.updateCachedAppsSnapshot((long) msg.obj);
+ } break;
}
}
}
@@ -4598,8 +4603,7 @@
boolean isRestrictedBackupMode = false;
if (backupTarget != null && backupTarget.appInfo.packageName.equals(processName)) {
isRestrictedBackupMode = backupTarget.appInfo.uid >= FIRST_APPLICATION_UID
- && ((backupTarget.backupMode == BackupRecord.RESTORE)
- || (backupTarget.backupMode == BackupRecord.RESTORE_FULL)
+ && ((backupTarget.backupMode == BackupRecord.RESTORE_FULL)
|| (backupTarget.backupMode == BackupRecord.BACKUP_FULL));
}
@@ -7311,7 +7315,14 @@
// Send broadcast to shell to trigger bugreport using Bugreport API
// Always start the shell process on the current user to ensure that
// the foreground user can see all bugreport notifications.
- mContext.sendBroadcastAsUser(triggerShellBugreport, getCurrentUser().getUserHandle());
+ // In case of BUGREPORT_MODE_REMOTE send the broadcast to SYSTEM user as the device
+ // owner apps are running on the SYSTEM user.
+ if (bugreportType == BugreportParams.BUGREPORT_MODE_REMOTE) {
+ mContext.sendBroadcastAsUser(triggerShellBugreport, UserHandle.SYSTEM);
+ } else {
+ mContext.sendBroadcastAsUser(triggerShellBugreport,
+ getCurrentUser().getUserHandle());
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -13382,7 +13393,8 @@
BackupRecord r = new BackupRecord(app, backupMode, targetUserId, backupDestination);
ComponentName hostingName =
- (backupMode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL)
+ (backupMode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL
+ || backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE)
? new ComponentName(app.packageName, app.backupAgentName)
: new ComponentName("android", "FullBackupAgent");
@@ -18598,6 +18610,13 @@
@MediaProjectionTokenEvent int event) {
ActivityManagerService.this.notifyMediaProjectionEvent(uid, projectionToken, event);
}
+
+ @Override
+ @NonNull
+ public StatsEvent getCachedAppsHighWatermarkStats(int atomTag, boolean resetAfterPull) {
+ return mAppProfiler.mCachedAppsWatermarkData.getCachedAppsHighWatermarkStats(
+ atomTag, resetAfterPull);
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, TimeoutRecord timeoutRecord) {
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 25ac956..f29a2e1 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -82,17 +82,21 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.util.StatsEvent;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.os.BinderInternal;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.MemInfoReader;
+import com.android.internal.util.QuickSelect;
import com.android.server.am.LowMemDetector.MemFactor;
import com.android.server.power.stats.BatteryStatsImpl;
import com.android.server.utils.PriorityDump;
@@ -323,6 +327,8 @@
private final ActivityManagerService mService;
private final Handler mBgHandler;
+ final CachedAppsWatermarkData mCachedAppsWatermarkData = new CachedAppsWatermarkData();
+
/**
* The lock to guard some of the profiling data here and {@link ProcessProfileRecord}.
*
@@ -391,6 +397,193 @@
}
}
+ /**
+ * A simple data class holding the information about the cached apps high watermark.
+ *
+ * Keep it sync with the frameworks/proto_logging/stats/atoms.proto
+ */
+ class CachedAppsWatermarkData {
+ /** The high water mark of the number of cached apps. */
+ @GuardedBy("mProcLock")
+ int mCachedAppHighWatermark;
+
+ /**
+ * The uptime (in seconds) at the high watermark.
+ * Note this is going to be pull metrics, so we'll need the timestamp here.
+ */
+ @GuardedBy("mProcLock")
+ int mUptimeInSeconds;
+
+ /** The number of binder proxy at that high water mark. */
+ @GuardedBy("mProcLock")
+ int mBinderProxySnapshot;
+
+ /** Free physical memory (in kb) on device. */
+ @GuardedBy("mProcLock")
+ int mFreeInKb;
+
+ /** Cched physical memory (in kb) on device. */
+ @GuardedBy("mProcLock")
+ int mCachedInKb;
+
+ /** zram (in kb) on device. */
+ @GuardedBy("mProcLock")
+ int mZramInKb;
+
+ /** Kernel memory (in kb) on device. */
+ @GuardedBy("mProcLock")
+ int mKernelInKb;
+
+ /** The number of apps in frozen state. */
+ @GuardedBy("mProcLock")
+ int mNumOfFrozenApps;
+
+ /** The longest frozen time (now - last_frozen) in current frozen apps. */
+ @GuardedBy("mProcLock")
+ int mLongestFrozenTimeInSeconds;
+
+ /** The shortest frozen time (now - last_frozen) in current frozen apps. */
+ @GuardedBy("mProcLock")
+ int mShortestFrozenTimeInSeconds;
+
+ /** The mean frozen time (now - last_frozen) in current frozen apps. */
+ @GuardedBy("mProcLock")
+ int mMeanFrozenTimeInSeconds;
+
+ /** The average frozen time (now - last_frozen) in current frozen apps. */
+ @GuardedBy("mProcLock")
+ int mAverageFrozenTimeInSeconds;
+
+ /**
+ * This is an array holding the frozen app durations temporarily
+ * while updating the cached app high watermark.
+ */
+ @GuardedBy("mProcLock")
+ private long[] mCachedAppFrozenDurations;
+
+ /**
+ * The earliest frozen timestamp within the frozen apps.
+ */
+ @GuardedBy("mProcLock")
+ private long mEarliestFrozenTimestamp;
+
+ /**
+ * The most recent frozen timestamp within the frozen apps.
+ */
+ @GuardedBy("mProcLock")
+ private long mLatestFrozenTimestamp;
+
+ /**
+ * The sum of total frozen durations of all frozen apps.
+ */
+ @GuardedBy("mProcLock")
+ private long mTotalFrozenDurations;
+
+ @GuardedBy("mProcLock")
+ void updateCachedAppsHighWatermarkIfNecessaryLocked(int numOfCachedApps, long now) {
+ if (numOfCachedApps > mCachedAppHighWatermark) {
+ mCachedAppHighWatermark = numOfCachedApps;
+ mUptimeInSeconds = (int) (now / 1000);
+
+ // The rest of the updates are pretty costly, do it in a separated handler.
+ mService.mHandler.removeMessages(
+ ActivityManagerService.UPDATE_CACHED_APP_HIGH_WATERMARK);
+ mService.mHandler.obtainMessage(
+ ActivityManagerService.UPDATE_CACHED_APP_HIGH_WATERMARK, Long.valueOf(now))
+ .sendToTarget();
+ }
+ }
+
+ void updateCachedAppsSnapshot(long now) {
+ synchronized (mProcLock) {
+ mEarliestFrozenTimestamp = now;
+ mLatestFrozenTimestamp = 0L;
+ mTotalFrozenDurations = 0L;
+ mNumOfFrozenApps = 0;
+ if (mCachedAppFrozenDurations == null
+ || mCachedAppFrozenDurations.length < mCachedAppHighWatermark) {
+ mCachedAppFrozenDurations = new long[Math.max(
+ mCachedAppHighWatermark, mService.mConstants.CUR_MAX_CACHED_PROCESSES)];
+ }
+ mService.mProcessList.forEachLruProcessesLOSP(true, app -> {
+ if (app.mOptRecord.isFrozen()) {
+ final long freezeTime = app.mOptRecord.getFreezeUnfreezeTime();
+ if (freezeTime < mEarliestFrozenTimestamp) {
+ mEarliestFrozenTimestamp = freezeTime;
+ }
+ if (freezeTime > mLatestFrozenTimestamp) {
+ mLatestFrozenTimestamp = freezeTime;
+ }
+ final long duration = now - freezeTime;
+ mTotalFrozenDurations += duration;
+ mCachedAppFrozenDurations[mNumOfFrozenApps++] = duration;
+ }
+ });
+ if (mNumOfFrozenApps > 0) {
+ mLongestFrozenTimeInSeconds = (int) ((now - mEarliestFrozenTimestamp) / 1000);
+ mShortestFrozenTimeInSeconds = (int) ((now - mLatestFrozenTimestamp) / 1000);
+ mAverageFrozenTimeInSeconds =
+ (int) ((mTotalFrozenDurations / mNumOfFrozenApps) / 1000);
+ mMeanFrozenTimeInSeconds = (int) (QuickSelect.select(mCachedAppFrozenDurations,
+ 0, mNumOfFrozenApps, mNumOfFrozenApps / 2) / 1000);
+ }
+
+ mBinderProxySnapshot = 0;
+ final SparseIntArray counts = BinderInternal.nGetBinderProxyPerUidCounts();
+ if (counts != null) {
+ for (int i = 0, size = counts.size(); i < size; i++) {
+ final int uid = counts.keyAt(i);
+ final UidRecord uidRec = mService.mProcessList.getUidRecordLOSP(uid);
+ if (uidRec != null) {
+ mBinderProxySnapshot += counts.valueAt(i);
+ }
+ }
+ }
+
+ final MemInfoReader memInfo = new MemInfoReader();
+ memInfo.readMemInfo();
+ mFreeInKb = (int) memInfo.getFreeSizeKb();
+ mCachedInKb = (int) memInfo.getCachedSizeKb();
+ mZramInKb = (int) memInfo.getZramTotalSizeKb();
+ mKernelInKb = (int) memInfo.getKernelUsedSizeKb();
+ }
+ }
+
+ @NonNull
+ StatsEvent getCachedAppsHighWatermarkStats(int atomTag, boolean resetAfterPull) {
+ synchronized (mProcLock) {
+ final StatsEvent event = FrameworkStatsLog.buildStatsEvent(atomTag,
+ mCachedAppHighWatermark,
+ mUptimeInSeconds,
+ mBinderProxySnapshot,
+ mFreeInKb,
+ mCachedInKb,
+ mZramInKb,
+ mKernelInKb,
+ mNumOfFrozenApps,
+ mLongestFrozenTimeInSeconds,
+ mShortestFrozenTimeInSeconds,
+ mMeanFrozenTimeInSeconds,
+ mAverageFrozenTimeInSeconds);
+ if (resetAfterPull) {
+ mCachedAppHighWatermark = 0;
+ mUptimeInSeconds = 0;
+ mBinderProxySnapshot = 0;
+ mFreeInKb = 0;
+ mCachedInKb = 0;
+ mZramInKb = 0;
+ mKernelInKb = 0;
+ mNumOfFrozenApps = 0;
+ mLongestFrozenTimeInSeconds = 0;
+ mShortestFrozenTimeInSeconds = 0;
+ mMeanFrozenTimeInSeconds = 0;
+ mAverageFrozenTimeInSeconds = 0;
+ }
+ return event;
+ }
+ }
+ }
+
private class BgHandler extends Handler {
static final int COLLECT_PSS_BG_MSG = 1;
static final int DEFER_PSS_MSG = 2;
@@ -954,7 +1147,7 @@
}
@GuardedBy({"mService", "mProcLock"})
- boolean updateLowMemStateLSP(int numCached, int numEmpty, int numTrimming) {
+ boolean updateLowMemStateLSP(int numCached, int numEmpty, int numTrimming, long now) {
int memFactor;
if (mLowMemDetector != null && mLowMemDetector.isAvailable()) {
memFactor = mLowMemDetector.getMemFactor();
@@ -1040,11 +1233,10 @@
mLastNumProcesses = mService.mProcessList.getLruSizeLOSP();
boolean allChanged;
int trackerMemFactor;
- final long now;
synchronized (mService.mProcessStats.mLock) {
- now = SystemClock.uptimeMillis();
allChanged = mService.mProcessStats.setMemFactorLocked(memFactor,
- mService.mAtmInternal == null || !mService.mAtmInternal.isSleeping(), now);
+ mService.mAtmInternal == null || !mService.mAtmInternal.isSleeping(),
+ SystemClock.uptimeMillis() /* re-acquire the time within the lock */);
trackerMemFactor = mService.mProcessStats.getMemFactorLocked();
}
if (memFactor != ADJ_MEM_FACTOR_NORMAL) {
@@ -1124,6 +1316,8 @@
profile.setTrimMemoryLevel(0);
});
}
+ mCachedAppsWatermarkData.updateCachedAppsHighWatermarkIfNecessaryLocked(
+ numCached + numEmpty, now);
return allChanged;
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index c3519d2..1e5f187 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1401,7 +1401,7 @@
mLastFreeSwapPercent = freeSwapPercent;
- return mService.mAppProfiler.updateLowMemStateLSP(numCached, numEmpty, numTrimming);
+ return mService.mAppProfiler.updateLowMemStateLSP(numCached, numEmpty, numTrimming, now);
}
@GuardedBy({"mService", "mProcLock"})
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 312f98a..d7b22a8 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -108,6 +108,7 @@
import android.os.UserHandle;
import android.os.storage.StorageManagerInternal;
import android.system.Os;
+import android.system.OsConstants;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -2331,9 +2332,15 @@
if (!regularZygote) {
// webview and app zygote don't have the permission to create the nodes
- if (Process.createProcessGroup(uid, startResult.pid) < 0) {
- throw new AssertionError("Unable to create process group for " + app.processName
- + " (" + startResult.pid + ")");
+ final int res = Process.createProcessGroup(uid, startResult.pid);
+ if (res < 0) {
+ if (res == -OsConstants.ESRCH) {
+ Slog.e(ActivityManagerService.TAG, "Unable to create process group for "
+ + app.processName + " (" + startResult.pid + ")");
+ } else {
+ throw new AssertionError("Unable to create process group for "
+ + app.processName + " (" + startResult.pid + ")");
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index a875860..78aafeb 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -176,6 +176,13 @@
boolean mAllowWhileInUsePermissionInFgs;
@PowerExemptionManager.ReasonCode
int mAllowWhileInUsePermissionInFgsReason;
+
+ // Integer version of mAllowWhileInUsePermissionInFgs that we keep track to compare
+ // the old and new logics.
+ // TODO: Remove them once we're confident in the new logic.
+ int mDebugWhileInUseReasonInStartForeground = REASON_DENIED;
+ int mDebugWhileInUseReasonInBindService = REASON_DENIED;
+
// A copy of mAllowWhileInUsePermissionInFgs's value when the service is entering FGS state.
boolean mAllowWhileInUsePermissionInFgsAtEntering;
/** Allow scheduling user-initiated jobs from the background. */
@@ -216,8 +223,13 @@
// created. (i.e. due to "bound" or "start".) It never decreases, even when stopForeground()
// is called.
int mStartForegroundCount;
- // Last time mAllowWhileInUsePermissionInFgs or mAllowStartForeground is set.
- long mLastSetFgsRestrictionTime;
+
+ // Last time mAllowWhileInUsePermissionInFgs or mAllowStartForeground was set to "allowed"
+ // from "disallowed" when the service was _not_ already a foreground service.
+ // this means they're set in startService(). (not startForegroundService)
+ // In startForeground(), if this timestamp is too old, we can't trust these flags, so
+ // we need to reset them.
+ long mLastUntrustedSetFgsRestrictionAllowedTime;
// This is a service record of a FGS delegate (not a service record of a real service)
boolean mIsFgsDelegate;
@@ -609,10 +621,14 @@
pw.print(prefix); pw.print("mIsAllowedBgActivityStartsByStart=");
pw.println(mBackgroundStartPrivilegesByStartMerged);
}
- pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
- pw.println(mAllowWhileInUsePermissionInFgs);
pw.print(prefix); pw.print("mAllowWhileInUsePermissionInFgsReason=");
pw.println(mAllowWhileInUsePermissionInFgsReason);
+
+ pw.print(prefix); pw.print("debugWhileInUseReasonInStartForeground=");
+ pw.println(mDebugWhileInUseReasonInStartForeground);
+ pw.print(prefix); pw.print("debugWhileInUseReasonInBindService=");
+ pw.println(mDebugWhileInUseReasonInBindService);
+
pw.print(prefix); pw.print("allowUiJobScheduling="); pw.println(mAllowUiJobScheduling);
pw.print(prefix); pw.print("recentCallingPackage=");
pw.println(mRecentCallingPackage);
@@ -624,6 +640,10 @@
pw.println(mStartForegroundCount);
pw.print(prefix); pw.print("infoAllowStartForeground=");
pw.println(mInfoAllowStartForeground);
+
+ pw.print(prefix); pw.print("lastUntrustedSetFgsRestrictionAllowedTime=");
+ TimeUtils.formatDuration(mLastUntrustedSetFgsRestrictionAllowedTime, now, pw);
+
if (delayed) {
pw.print(prefix); pw.print("delayed="); pw.println(delayed);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index a3163e0..02c4770 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2284,8 +2284,8 @@
synchronized (VolumeStreamState.class) {
mStreamStates[AudioSystem.STREAM_DTMF]
.setAllIndexes(mStreamStates[dtmfStreamAlias], caller);
- mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].mVolumeIndexSettingName =
- System.VOLUME_SETTINGS_INT[a11yStreamAlias];
+ mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setSettingName(
+ System.VOLUME_SETTINGS_INT[a11yStreamAlias]);
mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
mStreamStates[a11yStreamAlias], caller);
}
@@ -7700,7 +7700,7 @@
private int mPublicStreamType = AudioSystem.STREAM_MUSIC;
private AudioAttributes mAudioAttributes = AudioProductStrategy.getDefaultAttributes();
private boolean mIsMuted = false;
- private final String mSettingName;
+ private String mSettingName;
// No API in AudioSystem to get a device from strategy or from attributes.
// Need a valid public stream type to use current API getDeviceForStream
@@ -8029,15 +8029,19 @@
}
private void persistVolumeGroup(int device) {
- if (mUseFixedVolume) {
+ // No need to persist the index if the volume group is backed up
+ // by a public stream type as this is redundant
+ if (mUseFixedVolume || mHasValidStreamType) {
return;
}
if (DEBUG_VOL) {
Log.v(TAG, "persistVolumeGroup: storing index " + getIndex(device) + " for group "
+ mAudioVolumeGroup.name()
+ ", device " + AudioSystem.getOutputDeviceName(device)
- + " and User=" + getCurrentUserId());
+ + " and User=" + getCurrentUserId()
+ + " mSettingName: " + mSettingName);
}
+
boolean success = mSettings.putSystemIntForUser(mContentResolver,
getSettingNameForDevice(device),
getIndex(device),
@@ -8100,6 +8104,14 @@
return mSettingName + "_" + AudioSystem.getOutputDeviceName(device);
}
+ void setSettingName(String settingName) {
+ mSettingName = settingName;
+ }
+
+ String getSettingName() {
+ return mSettingName;
+ }
+
private void dump(PrintWriter pw) {
pw.println("- VOLUME GROUP " + mAudioVolumeGroup.name() + ":");
pw.print(" Muted: ");
@@ -8242,6 +8254,9 @@
*/
public void setVolumeGroupState(VolumeGroupState volumeGroupState) {
mVolumeGroupState = volumeGroupState;
+ if (mVolumeGroupState != null) {
+ mVolumeGroupState.setSettingName(mVolumeIndexSettingName);
+ }
}
/**
* Update the minimum index that can be used without MODIFY_AUDIO_SETTINGS permission
@@ -8315,6 +8330,17 @@
return (mVolumeIndexSettingName != null && !mVolumeIndexSettingName.isEmpty());
}
+ void setSettingName(String settingName) {
+ mVolumeIndexSettingName = settingName;
+ if (mVolumeGroupState != null) {
+ mVolumeGroupState.setSettingName(mVolumeIndexSettingName);
+ }
+ }
+
+ String getSettingName() {
+ return mVolumeIndexSettingName;
+ }
+
public void readSettings() {
synchronized (mSettingsLock) {
synchronized (VolumeStreamState.class) {
@@ -8989,7 +9015,7 @@
if (streamState.hasValidSettingsName()) {
mSettings.putSystemIntForUser(mContentResolver,
streamState.getSettingNameForDevice(device),
- (streamState.getIndex(device) + 5)/ 10,
+ (streamState.getIndex(device) + 5) / 10,
UserHandle.USER_CURRENT);
}
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 1f4c7e6f..1dc2725 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -152,6 +152,7 @@
import com.android.internal.net.VpnProfile;
import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.BinderUtils;
+import com.android.net.module.util.LinkPropertiesUtils;
import com.android.net.module.util.NetdUtils;
import com.android.net.module.util.NetworkStackConstants;
import com.android.server.DeviceIdleInternal;
@@ -230,7 +231,35 @@
* <p>If retries have exceeded the length of this array, the last entry in the array will be
* used as a repeating interval.
*/
- private static final long[] IKEV2_VPN_RETRY_DELAYS_SEC = {1L, 2L, 5L, 30L, 60L, 300L, 900L};
+ private static final long[] IKEV2_VPN_RETRY_DELAYS_MS =
+ {1_000L, 2_000L, 5_000L, 30_000L, 60_000L, 300_000L, 900_000L};
+
+ /**
+ * A constant to pass to {@link IkeV2VpnRunner#scheduleStartIkeSession(long)} to mean the
+ * delay should be computed automatically with backoff.
+ */
+ private static final long RETRY_DELAY_AUTO_BACKOFF = -1;
+
+ /**
+ * How long to wait before trying to migrate the IKE connection when NetworkCapabilities or
+ * LinkProperties change in a way that may require migration.
+ *
+ * This delay is useful to avoid multiple migration tries (e.g. when a network changes
+ * both its NC and LP at the same time, e.g. when it first connects) and to minimize the
+ * cases where an old list of addresses is detected for the network.
+ *
+ * In practice, the IKE library reads the LinkProperties of the passed network with
+ * the synchronous {@link ConnectivityManager#getLinkProperties(Network)}, which means in
+ * most cases the race would resolve correctly, but this delay increases the chance that
+ * it correctly is.
+ * Further, using the synchronous method in the IKE library is actually dangerous because
+ * it is racy (it races with {@code IkeNetworkCallbackBase#onLost} and it should be fixed
+ * by using callbacks instead. When that happens, the race within IKE is fixed but the
+ * race between that callback and the one in IkeV2VpnRunner becomes a much bigger problem,
+ * and this delay will be necessary to ensure the correct link address list is used.
+ */
+ private static final long IKE_DELAY_ON_NC_LP_CHANGE_MS = 300;
+
/**
* Largest profile size allowable for Platform VPNs.
*
@@ -619,14 +648,14 @@
/**
* Retrieves the next retry delay
*
- * <p>If retries have exceeded the IKEV2_VPN_RETRY_DELAYS_SEC, the last entry in
+ * <p>If retries have exceeded the size of IKEV2_VPN_RETRY_DELAYS_MS, the last entry in
* the array will be used as a repeating interval.
*/
- public long getNextRetryDelaySeconds(int retryCount) {
- if (retryCount >= IKEV2_VPN_RETRY_DELAYS_SEC.length) {
- return IKEV2_VPN_RETRY_DELAYS_SEC[IKEV2_VPN_RETRY_DELAYS_SEC.length - 1];
+ public long getNextRetryDelayMs(int retryCount) {
+ if (retryCount >= IKEV2_VPN_RETRY_DELAYS_MS.length) {
+ return IKEV2_VPN_RETRY_DELAYS_MS[IKEV2_VPN_RETRY_DELAYS_MS.length - 1];
} else {
- return IKEV2_VPN_RETRY_DELAYS_SEC[retryCount];
+ return IKEV2_VPN_RETRY_DELAYS_MS[retryCount];
}
}
@@ -679,6 +708,14 @@
boolean isIpv4) {
return MtuUtils.getMtu(childProposals, maxMtu, underlyingMtu, isIpv4);
}
+
+ /** Verify the binder calling UID is the one passed in arguments */
+ public void verifyCallingUidAndPackage(Context context, String packageName, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ if (getAppUid(context, packageName, userId) != callingUid) {
+ throw new SecurityException(packageName + " does not belong to uid " + callingUid);
+ }
+ }
}
@VisibleForTesting
@@ -726,7 +763,7 @@
mUserManager = mContext.getSystemService(UserManager.class);
mPackage = VpnConfig.LEGACY_VPN;
- mOwnerUID = getAppUid(mPackage, mUserId);
+ mOwnerUID = getAppUid(mContext, mPackage, mUserId);
mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(mPackage);
try {
@@ -823,7 +860,7 @@
}
/**
- * Chooses whether to force all connections to go though VPN.
+ * Chooses whether to force all connections to go through VPN.
*
* Used to enable/disable legacy VPN lockdown.
*
@@ -831,7 +868,7 @@
* {@link #setAlwaysOnPackage(String, boolean, List<String>)}; previous settings from calling
* that function will be replaced and saved with the always-on state.
*
- * @param lockdown whether to prevent all traffic outside of a VPN.
+ * @param lockdown whether to prevent all traffic outside of the VPN.
*/
public synchronized void setLockdown(boolean lockdown) {
enforceControlPermissionOrInternalCaller();
@@ -1108,6 +1145,7 @@
mAlwaysOn = false;
}
+ final boolean oldLockdownState = mLockdown;
mLockdown = (mAlwaysOn && lockdown);
mLockdownAllowlist = (mLockdown && lockdownAllowlist != null)
? Collections.unmodifiableList(new ArrayList<>(lockdownAllowlist))
@@ -1118,6 +1156,13 @@
if (isCurrentPreparedPackage(packageName)) {
updateAlwaysOnNotification(mNetworkInfo.getDetailedState());
setVpnForcedLocked(mLockdown);
+
+ // Lockdown forces the VPN to be non-bypassable (see #agentConnect) because it makes
+ // no sense for a VPN to be bypassable when connected but not when not connected.
+ // As such, changes in lockdown need to restart the agent.
+ if (mNetworkAgent != null && oldLockdownState != mLockdown) {
+ startNewNetworkAgent(mNetworkAgent, "Lockdown mode changed");
+ }
} else {
// Prepare this app. The notification will update as a side-effect of updateState().
// It also calls setVpnForcedLocked().
@@ -1355,7 +1400,8 @@
// We can't just check that packageName matches mPackage, because if the app was uninstalled
// and reinstalled it will no longer be prepared. Similarly if there is a shared UID, the
// calling package may not be the same as the prepared package. Check both UID and package.
- return getAppUid(packageName, mUserId) == mOwnerUID && mPackage.equals(packageName);
+ return getAppUid(mContext, packageName, mUserId) == mOwnerUID
+ && mPackage.equals(packageName);
}
/** Prepare the VPN for the given package. Does not perform permission checks. */
@@ -1396,7 +1442,7 @@
Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
mPackage = newPackage;
- mOwnerUID = getAppUid(newPackage, mUserId);
+ mOwnerUID = getAppUid(mContext, newPackage, mUserId);
mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(newPackage);
try {
mNms.allowProtect(mOwnerUID);
@@ -1417,7 +1463,7 @@
// Check if the caller is authorized.
enforceControlPermissionOrInternalCaller();
- final int uid = getAppUid(packageName, mUserId);
+ final int uid = getAppUid(mContext, packageName, mUserId);
if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) {
// Authorization for nonexistent packages (or fake ones) can't be updated.
return false;
@@ -1497,11 +1543,11 @@
|| isVpnServicePreConsented(context, packageName);
}
- private int getAppUid(final String app, final int userId) {
+ private static int getAppUid(final Context context, final String app, final int userId) {
if (VpnConfig.LEGACY_VPN.equals(app)) {
return Process.myUid();
}
- PackageManager pm = mContext.getPackageManager();
+ PackageManager pm = context.getPackageManager();
final long token = Binder.clearCallingIdentity();
try {
return pm.getPackageUidAsUser(app, userId);
@@ -1630,6 +1676,10 @@
*/
private boolean updateLinkPropertiesInPlaceIfPossible(NetworkAgent agent, VpnConfig oldConfig) {
// NetworkAgentConfig cannot be updated without registering a new NetworkAgent.
+ // Strictly speaking, bypassability is affected by lockdown and therefore it's possible
+ // it doesn't actually change even if mConfig.allowBypass changed. It might be theoretically
+ // possible to do handover in this case, but this is far from obvious to VPN authors and
+ // it's simpler if the rule is just "can't update in place if you change allow bypass".
if (oldConfig.allowBypass != mConfig.allowBypass) {
Log.i(TAG, "Handover not possible due to changes to allowBypass");
return false;
@@ -1671,10 +1721,11 @@
mLegacyState = LegacyVpnInfo.STATE_CONNECTING;
updateState(DetailedState.CONNECTING, "agentConnect");
+ final boolean bypassable = mConfig.allowBypass && !mLockdown;
final NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig.Builder()
.setLegacyType(ConnectivityManager.TYPE_VPN)
.setLegacyTypeName("VPN")
- .setBypassableVpn(mConfig.allowBypass && !mLockdown)
+ .setBypassableVpn(bypassable)
.setVpnRequiresValidation(mConfig.requiresInternetValidation)
.setLocalRoutesExcludedForVpn(mConfig.excludeLocalRoutes)
.build();
@@ -1688,7 +1739,7 @@
capsBuilder.setTransportInfo(new VpnTransportInfo(
getActiveVpnType(),
mConfig.session,
- mConfig.allowBypass,
+ bypassable,
expensive));
// Only apps targeting Q and above can explicitly declare themselves as metered.
@@ -1719,6 +1770,10 @@
Binder.restoreCallingIdentity(token);
}
updateState(DetailedState.CONNECTED, "agentConnect");
+ if (isIkev2VpnRunner()) {
+ final IkeSessionWrapper session = ((IkeV2VpnRunner) mVpnRunner).mSession;
+ if (null != session) session.setUnderpinnedNetwork(mNetworkAgent.getNetwork());
+ }
}
private static boolean areLongLivedTcpConnectionsExpensive(@NonNull VpnRunner runner) {
@@ -1913,7 +1968,7 @@
private SortedSet<Integer> getAppsUids(List<String> packageNames, int userId) {
SortedSet<Integer> uids = new TreeSet<>();
for (String app : packageNames) {
- int uid = getAppUid(app, userId);
+ int uid = getAppUid(mContext, app, userId);
if (uid != -1) uids.add(uid);
// TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
// ConnectivityServiceTest.
@@ -3232,7 +3287,6 @@
prepareStatusIntent();
}
agentConnect(this::onValidationStatus);
- mSession.setUnderpinnedNetwork(mNetworkAgent.getNetwork());
return; // Link properties are already sent.
} else {
// Underlying networks also set in agentConnect()
@@ -3349,7 +3403,6 @@
if (!removedAddrs.isEmpty()) {
startNewNetworkAgent(
mNetworkAgent, "MTU too low for IPv6; restarting network agent");
- mSession.setUnderpinnedNetwork(mNetworkAgent.getNetwork());
for (LinkAddress removed : removedAddrs) {
mTunnelIface.removeAddress(
@@ -3628,7 +3681,7 @@
final VpnTransportInfo info = new VpnTransportInfo(
getActiveVpnType(),
mConfig.session,
- mConfig.allowBypass,
+ mConfig.allowBypass && !mLockdown,
areLongLivedTcpConnectionsExpensive(keepaliveDelaySec));
final boolean ncUpdateRequired = !info.equals(mNetworkCapabilities.getTransportInfo());
if (ncUpdateRequired) {
@@ -3718,13 +3771,20 @@
}
}
- private void scheduleRetryNewIkeSession() {
+ /**
+ * Schedule starting an IKE session.
+ * @param delayMs the delay after which to try starting the session. This should be
+ * RETRY_DELAY_AUTO_BACKOFF for automatic retries with backoff.
+ */
+ private void scheduleStartIkeSession(final long delayMs) {
if (mScheduledHandleRetryIkeSessionFuture != null) {
Log.d(TAG, "There is a pending retrying task, skip the new retrying task");
return;
}
- final long retryDelay = mDeps.getNextRetryDelaySeconds(mRetryCount++);
- Log.d(TAG, "Retry new IKE session after " + retryDelay + " seconds.");
+ final long retryDelayMs = RETRY_DELAY_AUTO_BACKOFF != delayMs
+ ? delayMs
+ : mDeps.getNextRetryDelayMs(mRetryCount++);
+ Log.d(TAG, "Retry new IKE session after " + retryDelayMs + " milliseconds.");
// If the default network is lost during the retry delay, the mActiveNetwork will be
// null, and the new IKE session won't be established until there is a new default
// network bringing up.
@@ -3735,7 +3795,7 @@
// Reset mScheduledHandleRetryIkeSessionFuture since it's already run on
// executor thread.
mScheduledHandleRetryIkeSessionFuture = null;
- }, retryDelay, TimeUnit.SECONDS);
+ }, retryDelayMs, TimeUnit.MILLISECONDS);
}
/** Called when the NetworkCapabilities of underlying network is changed */
@@ -3747,15 +3807,23 @@
if (oldNc == null || !nc.getSubscriptionIds().equals(oldNc.getSubscriptionIds())) {
// A new default network is available, or the subscription has changed.
// Try to migrate the session, or failing that, start a new one.
- startOrMigrateIkeSession(mActiveNetwork);
+ scheduleStartIkeSession(IKE_DELAY_ON_NC_LP_CHANGE_MS);
}
}
/** Called when the LinkProperties of underlying network is changed */
public void onDefaultNetworkLinkPropertiesChanged(@NonNull LinkProperties lp) {
- mEventChanges.log("[UnderlyingNW] Lp changed from "
- + mUnderlyingLinkProperties + " to " + lp);
+ final LinkProperties oldLp = mUnderlyingLinkProperties;
+ mEventChanges.log("[UnderlyingNW] Lp changed from " + oldLp + " to " + lp);
mUnderlyingLinkProperties = lp;
+ if (oldLp == null || !LinkPropertiesUtils.isIdenticalAllLinkAddresses(oldLp, lp)) {
+ // If some of the link addresses changed, the IKE session may need to be migrated
+ // or restarted, for example if the available IP families have changed or if the
+ // source address used has gone away. See IkeConnectionController#onNetworkSetByUser
+ // and IkeConnectionController#selectAndSetRemoteAddress for where this ends up
+ // re-evaluating the session.
+ scheduleStartIkeSession(IKE_DELAY_ON_NC_LP_CHANGE_MS);
+ }
}
class VpnConnectivityDiagnosticsCallback
@@ -4033,7 +4101,7 @@
markFailedAndDisconnect(exception);
return;
} else {
- scheduleRetryNewIkeSession();
+ scheduleStartIkeSession(RETRY_DELAY_AUTO_BACKOFF);
}
// Close all obsolete state, but keep VPN alive incase a usable network comes up.
@@ -4470,10 +4538,7 @@
}
private void verifyCallingUidAndPackage(String packageName) {
- final int callingUid = Binder.getCallingUid();
- if (getAppUid(packageName, mUserId) != callingUid) {
- throw new SecurityException(packageName + " does not belong to uid " + callingUid);
- }
+ mDeps.verifyCallingUidAndPackage(mContext, packageName, mUserId);
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 85b4034..5d92c7f 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -119,7 +119,6 @@
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
import android.util.IntArray;
@@ -298,11 +297,10 @@
mDisplayWindowPolicyControllers = new SparseArray<>();
/**
- * Map of every internal primary display device {@link HighBrightnessModeMetadata}s indexed by
- * {@link DisplayDevice#mUniqueId}.
+ * Provides {@link HighBrightnessModeMetadata}s for {@link DisplayDevice}s.
*/
- public final ArrayMap<String, HighBrightnessModeMetadata> mHighBrightnessModeMetadataMap =
- new ArrayMap<>();
+ private final HighBrightnessModeMetadataMapper mHighBrightnessModeMetadataMapper =
+ new HighBrightnessModeMetadataMapper();
// List of all currently registered display adapters.
private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
@@ -1823,19 +1821,14 @@
DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
- final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
- if (device == null) {
- Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: "
- + display.getDisplayIdLocked());
- return;
- }
-
final int leadDisplayId = display.getLeadDisplayIdLocked();
updateDisplayPowerControllerLeaderLocked(dpc, leadDisplayId);
- final String uniqueId = device.getUniqueId();
- HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId);
- dpc.onDisplayChanged(hbmMetadata, leadDisplayId);
+ HighBrightnessModeMetadata hbmMetadata =
+ mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display);
+ if (hbmMetadata != null) {
+ dpc.onDisplayChanged(hbmMetadata, leadDisplayId);
+ }
}
}
@@ -1922,19 +1915,14 @@
final int displayId = display.getDisplayIdLocked();
final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
if (dpc != null) {
- final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
- if (device == null) {
- Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: "
- + display.getDisplayIdLocked());
- return;
- }
-
final int leadDisplayId = display.getLeadDisplayIdLocked();
updateDisplayPowerControllerLeaderLocked(dpc, leadDisplayId);
- final String uniqueId = device.getUniqueId();
- HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId);
- dpc.onDisplayChanged(hbmMetadata, leadDisplayId);
+ HighBrightnessModeMetadata hbmMetadata =
+ mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display);
+ if (hbmMetadata != null) {
+ dpc.onDisplayChanged(hbmMetadata, leadDisplayId);
+ }
}
}
@@ -3073,26 +3061,6 @@
mLogicalDisplayMapper.forEachLocked(this::addDisplayPowerControllerLocked);
}
- private HighBrightnessModeMetadata getHighBrightnessModeMetadata(LogicalDisplay display) {
- final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
- if (device == null) {
- Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: "
- + display.getDisplayIdLocked());
- return null;
- }
-
- final String uniqueId = device.getUniqueId();
-
- if (mHighBrightnessModeMetadataMap.containsKey(uniqueId)) {
- return mHighBrightnessModeMetadataMap.get(uniqueId);
- }
-
- // HBM Time info not present. Create a new one for this physical display.
- HighBrightnessModeMetadata hbmInfo = new HighBrightnessModeMetadata();
- mHighBrightnessModeMetadataMap.put(uniqueId, hbmInfo);
- return hbmInfo;
- }
-
@RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
private void addDisplayPowerControllerLocked(LogicalDisplay display) {
if (mPowerHandler == null) {
@@ -3113,7 +3081,13 @@
// We also need to pass a mapping of the HighBrightnessModeTimeInfoMap to
// displayPowerController, so the hbm info can be correctly associated
// with the corresponding displaydevice.
- HighBrightnessModeMetadata hbmMetadata = getHighBrightnessModeMetadata(display);
+ HighBrightnessModeMetadata hbmMetadata =
+ mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display);
+ if (hbmMetadata == null) {
+ Slog.wtf(TAG, "High Brightness Mode Metadata is null in DisplayManagerService for "
+ + "display: " + display.getDisplayIdLocked());
+ return;
+ }
if (DeviceConfig.getBoolean("display_manager",
"use_newly_structured_display_power_controller", true)) {
displayPowerController = new DisplayPowerController2(
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 5e3990a..1acc208 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -514,6 +514,7 @@
private boolean mIsEnabled;
private boolean mIsInTransition;
+ private boolean mIsDisplayInternal;
// The id of the thermal brightness throttling policy that should be used.
private String mThermalBrightnessThrottlingDataId;
@@ -553,6 +554,8 @@
mDisplayStatsId = mUniqueDisplayId.hashCode();
mIsEnabled = logicalDisplay.isEnabledLocked();
mIsInTransition = logicalDisplay.isInTransitionLocked();
+ mIsDisplayInternal = logicalDisplay.getPrimaryDisplayDeviceLocked()
+ .getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL;
mHandler = new DisplayControllerHandler(handler.getLooper());
mLastBrightnessEvent = new BrightnessEvent(mDisplayId);
mTempBrightnessEvent = new BrightnessEvent(mDisplayId);
@@ -892,6 +895,9 @@
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
final boolean isEnabled = mLogicalDisplay.isEnabledLocked();
final boolean isInTransition = mLogicalDisplay.isInTransitionLocked();
+ final boolean isDisplayInternal = mLogicalDisplay.getPrimaryDisplayDeviceLocked() != null
+ && mLogicalDisplay.getPrimaryDisplayDeviceLocked()
+ .getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL;
final String thermalBrightnessThrottlingDataId =
mLogicalDisplay.getThermalBrightnessThrottlingDataIdLocked();
mHandler.postAtTime(() -> {
@@ -924,7 +930,7 @@
mIsEnabled = isEnabled;
mIsInTransition = isInTransition;
}
-
+ mIsDisplayInternal = isDisplayInternal;
if (changed) {
updatePowerState();
}
@@ -1810,10 +1816,11 @@
// TODO(b/216365040): The decision to prevent HBM for HDR in low power mode should be
// done in HighBrightnessModeController.
if (mHbmController.getHighBrightnessMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
- && (mBrightnessReason.getModifier() & BrightnessReason.MODIFIER_DIMMED) == 0
- && (mBrightnessReason.getModifier() & BrightnessReason.MODIFIER_LOW_POWER)
+ && (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_DIMMED) == 0
+ && (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_LOW_POWER)
== 0) {
- // We want to scale HDR brightness level with the SDR level
+ // We want to scale HDR brightness level with the SDR level, we also need to restore
+ // SDR brightness immediately when entering dim or low power mode.
animateValue = mHbmController.getHdrBrightnessValue();
}
@@ -3074,9 +3081,7 @@
event.getThermalMax() == PowerManager.BRIGHTNESS_MAX
? -1f : convertToNits(event.getThermalMax());
- if (mLogicalDisplay.getPrimaryDisplayDeviceLocked() != null
- && mLogicalDisplay.getPrimaryDisplayDeviceLocked()
- .getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL) {
+ if (mIsDisplayInternal) {
FrameworkStatsLog.write(FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED,
convertToNits(event.getInitialBrightness()),
convertToNits(event.getBrightness()),
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 23e606c..b36aede 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -399,6 +399,7 @@
private boolean mIsEnabled;
private boolean mIsInTransition;
+ private boolean mIsDisplayInternal;
// The id of the thermal brightness throttling policy that should be used.
private String mThermalBrightnessThrottlingDataId;
@@ -431,6 +432,8 @@
.getDisplayDeviceConfig();
mIsEnabled = logicalDisplay.isEnabledLocked();
mIsInTransition = logicalDisplay.isInTransitionLocked();
+ mIsDisplayInternal = logicalDisplay.getPrimaryDisplayDeviceLocked()
+ .getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL;
mWakelockController = mInjector.getWakelockController(mDisplayId, callbacks);
mDisplayPowerProximityStateController = mInjector.getDisplayPowerProximityStateController(
mWakelockController, mDisplayDeviceConfig, mHandler.getLooper(),
@@ -708,6 +711,9 @@
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
final boolean isEnabled = mLogicalDisplay.isEnabledLocked();
final boolean isInTransition = mLogicalDisplay.isInTransitionLocked();
+ final boolean isDisplayInternal = mLogicalDisplay.getPrimaryDisplayDeviceLocked() != null
+ && mLogicalDisplay.getPrimaryDisplayDeviceLocked()
+ .getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL;
final String thermalBrightnessThrottlingDataId =
mLogicalDisplay.getThermalBrightnessThrottlingDataIdLocked();
@@ -742,6 +748,7 @@
mIsInTransition = isInTransition;
}
+ mIsDisplayInternal = isDisplayInternal;
if (changed) {
updatePowerState();
}
@@ -1449,10 +1456,11 @@
// TODO(b/216365040): The decision to prevent HBM for HDR in low power mode should be
// done in HighBrightnessModeController.
if (mHbmController.getHighBrightnessMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
- && (mBrightnessReason.getModifier() & BrightnessReason.MODIFIER_DIMMED) == 0
- && (mBrightnessReason.getModifier() & BrightnessReason.MODIFIER_LOW_POWER)
+ && (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_DIMMED) == 0
+ && (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_LOW_POWER)
== 0) {
- // We want to scale HDR brightness level with the SDR level
+ // We want to scale HDR brightness level with the SDR level, we also need to restore
+ // SDR brightness immediately when entering dim or low power mode.
animateValue = mHbmController.getHdrBrightnessValue();
}
@@ -2217,6 +2225,7 @@
pw.println(" mSkipScreenOnBrightnessRamp=" + mSkipScreenOnBrightnessRamp);
pw.println(" mColorFadeFadesConfig=" + mColorFadeFadesConfig);
pw.println(" mColorFadeEnabled=" + mColorFadeEnabled);
+ pw.println(" mIsDisplayInternal=" + mIsDisplayInternal);
synchronized (mCachedBrightnessInfo) {
pw.println(" mCachedBrightnessInfo.brightness="
+ mCachedBrightnessInfo.brightness.value);
@@ -2434,9 +2443,7 @@
float appliedThermalCapNits =
event.getThermalMax() == PowerManager.BRIGHTNESS_MAX
? -1f : mDisplayBrightnessController.convertToNits(event.getThermalMax());
- if (mLogicalDisplay.getPrimaryDisplayDeviceLocked() != null
- && mLogicalDisplay.getPrimaryDisplayDeviceLocked()
- .getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL) {
+ if (mIsDisplayInternal) {
FrameworkStatsLog.write(FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED,
mDisplayBrightnessController.convertToNits(event.getInitialBrightness()),
mDisplayBrightnessController.convertToNits(event.getBrightness()),
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeMetadataMapper.java b/services/core/java/com/android/server/display/HighBrightnessModeMetadataMapper.java
new file mode 100644
index 0000000..76702d3
--- /dev/null
+++ b/services/core/java/com/android/server/display/HighBrightnessModeMetadataMapper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 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.server.display;
+
+import android.util.ArrayMap;
+import android.util.Slog;
+
+/**
+ * Provides {@link HighBrightnessModeMetadata}s for {@link DisplayDevice}s. This class should only
+ * be accessed from the display thread.
+ */
+class HighBrightnessModeMetadataMapper {
+
+ private static final String TAG = "HighBrightnessModeMetadataMapper";
+
+ /**
+ * Map of every internal primary display device {@link HighBrightnessModeMetadata}s indexed by
+ * {@link DisplayDevice#mUniqueId}.
+ */
+ private final ArrayMap<String, HighBrightnessModeMetadata> mHighBrightnessModeMetadataMap =
+ new ArrayMap<>();
+
+ HighBrightnessModeMetadata getHighBrightnessModeMetadataLocked(LogicalDisplay display) {
+ final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
+ if (device == null) {
+ Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: "
+ + display.getDisplayIdLocked());
+ return null;
+ }
+
+ final String uniqueId = device.getUniqueId();
+
+ if (mHighBrightnessModeMetadataMap.containsKey(uniqueId)) {
+ return mHighBrightnessModeMetadataMap.get(uniqueId);
+ }
+
+ // HBM Time info not present. Create a new one for this physical display.
+ HighBrightnessModeMetadata hbmInfo = new HighBrightnessModeMetadata();
+ mHighBrightnessModeMetadataMap.put(uniqueId, hbmInfo);
+ return hbmInfo;
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 9eedc4e..f47c4b2 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -682,7 +682,6 @@
@ServiceThreadOnly
private void launchDeviceDiscovery() {
assertRunOnServiceThread();
- clearDeviceInfoList();
DeviceDiscoveryAction action = new DeviceDiscoveryAction(this,
new DeviceDiscoveryCallback() {
@Override
@@ -691,13 +690,6 @@
mService.getHdmiCecNetwork().addCecDevice(info);
}
- // Since we removed all devices when it starts and
- // device discovery action does not poll local devices,
- // we should put device info of local device manually here
- for (HdmiCecLocalDevice device : mService.getAllCecLocalDevices()) {
- mService.getHdmiCecNetwork().addCecDevice(device.getDeviceInfo());
- }
-
mSelectRequestBuffer.process();
resetSelectRequestBuffer();
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 805ff66..75fe63a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1267,6 +1267,7 @@
// It's now safe to flush existing local devices from mCecController since they were
// already moved to 'localDevices'.
clearCecLocalDevices();
+ mHdmiCecNetwork.clearDeviceList();
allocateLogicalAddress(localDevices, initiatedBy);
}
@@ -1303,6 +1304,7 @@
HdmiControlManager.POWER_STATUS_ON, getCecVersion());
localDevice.setDeviceInfo(deviceInfo);
mHdmiCecNetwork.addLocalDevice(deviceType, localDevice);
+ mHdmiCecNetwork.addCecDevice(localDevice.getDeviceInfo());
mCecController.addLogicalAddress(logicalAddress);
allocatedDevices.add(localDevice);
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index d0669e7..5f45f91 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -686,13 +686,7 @@
@NonNull
private InputChannel createSpyWindowGestureMonitor(IBinder monitorToken, String name,
- int displayId, int pid, int uid) {
- final SurfaceControl sc = mWindowManagerCallbacks.createSurfaceForGestureMonitor(name,
- displayId);
- if (sc == null) {
- throw new IllegalArgumentException(
- "Could not create gesture monitor surface on display: " + displayId);
- }
+ SurfaceControl sc, int displayId, int pid, int uid) {
final InputChannel channel = createInputChannel(name);
try {
@@ -749,9 +743,18 @@
final long ident = Binder.clearCallingIdentity();
try {
- final InputChannel inputChannel =
- createSpyWindowGestureMonitor(monitorToken, name, displayId, pid, uid);
- return new InputMonitor(inputChannel, new InputMonitorHost(inputChannel.getToken()));
+ final SurfaceControl sc = mWindowManagerCallbacks.createSurfaceForGestureMonitor(name,
+ displayId);
+ if (sc == null) {
+ throw new IllegalArgumentException(
+ "Could not create gesture monitor surface on display: " + displayId);
+ }
+
+ final InputChannel inputChannel = createSpyWindowGestureMonitor(
+ monitorToken, name, sc, displayId, pid, uid);
+ return new InputMonitor(inputChannel,
+ new InputMonitorHost(inputChannel.getToken()),
+ new SurfaceControl(sc, "IMS.monitorGestureInput"));
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index b82e3a3..c076c05 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
+import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.media.RouteDiscoveryPreference;
import android.media.RoutingSessionInfo;
@@ -26,6 +27,7 @@
import com.android.internal.annotations.GuardedBy;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -108,6 +110,28 @@
&& mComponentName.getClassName().equals(className);
}
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + getDebugString());
+ prefix += " ";
+ if (mProviderInfo == null) {
+ pw.println(prefix + "<provider info not received, yet>");
+ } else if (mProviderInfo.getRoutes().isEmpty()) {
+ pw.println(prefix + "<provider info has no routes>");
+ } else {
+ for (MediaRoute2Info route : mProviderInfo.getRoutes()) {
+ pw.printf("%s%s | %s\n", prefix, route.getId(), route.getName());
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getDebugString();
+ }
+
+ /** Returns a human-readable string describing the instance, for debugging purposes. */
+ protected abstract String getDebugString();
+
public interface Callback {
void onProviderStateChanged(@Nullable MediaRoute2Provider provider);
void onSessionCreated(@NonNull MediaRoute2Provider provider,
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 90451b1..72b8436 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -44,7 +44,6 @@
import com.android.internal.annotations.GuardedBy;
-import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
@@ -83,10 +82,6 @@
mHandler = new Handler(Looper.myLooper());
}
- public void dump(PrintWriter pw, String prefix) {
- pw.println(prefix + getDebugString());
- }
-
public void setManagerScanning(boolean managerScanning) {
if (mIsManagerScanning != managerScanning) {
mIsManagerScanning = managerScanning;
@@ -488,11 +483,7 @@
}
@Override
- public String toString() {
- return getDebugString();
- }
-
- private String getDebugString() {
+ protected String getDebugString() {
return TextUtils.formatSimple(
"ProviderServiceProxy - package: %s, bound: %b, connection (active:%b, ready:%b)",
mComponentName.getPackageName(),
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 3c97aaf8..2d3b97b 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -1751,6 +1751,7 @@
String indent = prefix + " ";
pw.println(indent + "mRunning=" + mRunning);
+ mSystemProvider.dump(pw, prefix);
mWatcher.dump(pw, prefix);
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 5ea2ca4..464a256 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -16,14 +16,22 @@
package com.android.server.media;
+import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.PendingIntent;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
+import android.content.pm.ResolveInfo;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
@@ -42,6 +50,7 @@
import android.media.session.PlaybackState;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
@@ -52,6 +61,7 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
@@ -73,6 +83,17 @@
*/
// TODO(jaewan): Do not call service method directly -- introduce listener instead.
public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionRecordImpl {
+
+ /**
+ * {@link MediaSession#setMediaButtonBroadcastReceiver(ComponentName)} throws an {@link
+ * IllegalArgumentException} if the provided {@link ComponentName} does not resolve to a valid
+ * {@link android.content.BroadcastReceiver broadcast receiver} for apps targeting Android U and
+ * above. For apps targeting Android T and below, the request will be ignored.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ static final long THROW_FOR_INVALID_BROADCAST_RECEIVER = 270049379L;
+
private static final String TAG = "MediaSessionRecord";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -871,6 +892,22 @@
}
};
+ @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
+ private static boolean componentNameExists(
+ @NonNull ComponentName componentName, @NonNull Context context, int userId) {
+ Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mediaButtonIntent.setComponent(componentName);
+
+ UserHandle userHandle = UserHandle.of(userId);
+ PackageManager pm = context.getPackageManager();
+
+ List<ResolveInfo> resolveInfos =
+ pm.queryBroadcastReceiversAsUser(
+ mediaButtonIntent, PackageManager.ResolveInfoFlags.of(0), userHandle);
+ return !resolveInfos.isEmpty();
+ }
+
private final class SessionStub extends ISession.Stub {
@Override
public void destroySession() throws RemoteException {
@@ -955,7 +992,9 @@
}
@Override
+ @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
public void setMediaButtonBroadcastReceiver(ComponentName receiver) throws RemoteException {
+ final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
//mPackageName has been verified in MediaSessionService.enforcePackageName().
@@ -970,6 +1009,20 @@
!= 0) {
return;
}
+
+ if (!componentNameExists(receiver, mContext, mUserId)) {
+ if (CompatChanges.isChangeEnabled(THROW_FOR_INVALID_BROADCAST_RECEIVER, uid)) {
+ throw new IllegalArgumentException("Invalid component name: " + receiver);
+ } else {
+ Log.w(
+ TAG,
+ "setMediaButtonBroadcastReceiver(): "
+ + "Ignoring invalid component name="
+ + receiver);
+ }
+ return;
+ }
+
mMediaButtonReceiverHolder = MediaButtonReceiverHolder.create(mUserId, receiver);
mService.onMediaButtonReceiverChanged(MediaSessionRecord.this);
} finally {
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 5d5c621..6d2d2e4 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -392,6 +392,15 @@
mCallback.onSessionUpdated(this, sessionInfo);
}
+ @Override
+ protected String getDebugString() {
+ return TextUtils.formatSimple(
+ "SystemMR2Provider - package: %s, selected route id: %s, bluetooth impl: %s",
+ mComponentName.getPackageName(),
+ mSelectedRouteId,
+ mBluetoothRouteController.getClass().getSimpleName());
+ }
+
private static class SessionCreationRequest {
final long mRequestId;
final String mRouteId;
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index c1171fa..2704f56 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -38,6 +38,7 @@
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.PowerExemptionManager;
@@ -337,7 +338,7 @@
broadcastAllowlist, null /* filterExtrasForReceiver */, null);
// Send to PermissionController for all new users, even if it may not be running for some
// users
- if (isPrivacySafetyLabelChangeNotificationsEnabled()) {
+ if (isPrivacySafetyLabelChangeNotificationsEnabled(mContext)) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
packageName, extras, 0,
mContext.getPackageManager().getPermissionControllerPackageName(),
@@ -389,9 +390,13 @@
}
/** Returns whether the Safety Label Change notification, a privacy feature, is enabled. */
- public static boolean isPrivacySafetyLabelChangeNotificationsEnabled() {
+ public static boolean isPrivacySafetyLabelChangeNotificationsEnabled(Context context) {
+ PackageManager packageManager = context.getPackageManager();
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED, false);
+ SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED, false)
+ && !packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+ && !packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+ && !packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH);
}
@NonNull
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index ecd2a90..1e0c95c 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -2954,7 +2954,7 @@
}
// Send to PermissionController for all update users, even if it may not be running
// for some users
- if (BroadcastHelper.isPrivacySafetyLabelChangeNotificationsEnabled()) {
+ if (BroadcastHelper.isPrivacySafetyLabelChangeNotificationsEnabled(mContext)) {
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
mPm.mRequiredPermissionControllerPackage, null /*finishedReceiver*/,
diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java
index 5015985..7198de2 100644
--- a/services/core/java/com/android/server/pm/VerifyingSession.java
+++ b/services/core/java/com/android/server/pm/VerifyingSession.java
@@ -353,11 +353,10 @@
PackageInfoLite pkgLite,
PackageVerificationState verificationState) {
- // TODO: http://b/22976637
- // Apps installed for "all" users use the device owner to verify the app
+ // Apps installed for "all" users use the current user to verify the app
UserHandle verifierUser = getUser();
if (verifierUser == UserHandle.ALL) {
- verifierUser = UserHandle.SYSTEM;
+ verifierUser = UserHandle.of(mPm.mUserManager.getCurrentUserId());
}
final int verifierUserId = verifierUser.getIdentifier();
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 8640377..0ce17de 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -751,6 +751,8 @@
return pullPendingIntentsPerPackage(atomTag, data);
case FrameworkStatsLog.HDR_CAPABILITIES:
return pullHdrCapabilities(atomTag, data);
+ case FrameworkStatsLog.CACHED_APPS_HIGH_WATERMARK:
+ return pullCachedAppsHighWatermark(atomTag, data);
default:
throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
}
@@ -951,6 +953,7 @@
registerPendingIntentsPerPackagePuller();
registerPinnerServiceStats();
registerHdrCapabilitiesPuller();
+ registerCachedAppsHighWatermarkPuller();
}
private void initAndRegisterNetworkStatsPullers() {
@@ -4732,6 +4735,12 @@
return StatsManager.PULL_SUCCESS;
}
+ private int pullCachedAppsHighWatermark(int atomTag, List<StatsEvent> pulledData) {
+ pulledData.add(LocalServices.getService(ActivityManagerInternal.class)
+ .getCachedAppsHighWatermarkStats(atomTag, true));
+ return StatsManager.PULL_SUCCESS;
+ }
+
private boolean hasDolbyVisionIssue(Display display) {
AtomicInteger modesSupportingDolbyVision = new AtomicInteger();
Arrays.stream(display.getSupportedModes())
@@ -4777,6 +4786,16 @@
);
}
+ private void registerCachedAppsHighWatermarkPuller() {
+ final int tagId = FrameworkStatsLog.CACHED_APPS_HIGH_WATERMARK;
+ mStatsManager.setPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ DIRECT_EXECUTOR,
+ mStatsCallbackImpl
+ );
+ }
+
int pullSystemServerPinnerStats(int atomTag, List<StatsEvent> pulledData) {
PinnerService pinnerService = LocalServices.getService(PinnerService.class);
List<PinnedFileStats> pinnedFileStats = pinnerService.dumpDataForStatsd();
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index a757d90..f71f3b1 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -397,9 +397,21 @@
/** Returns {@code true} if the incoming activity can belong to this transition. */
boolean canCoalesce(ActivityRecord r) {
- return mLastLaunchedActivity.mDisplayContent == r.mDisplayContent
- && mLastLaunchedActivity.getTask().getBounds().equals(r.getTask().getBounds())
- && mLastLaunchedActivity.getWindowingMode() == r.getWindowingMode();
+ if (mLastLaunchedActivity.mDisplayContent != r.mDisplayContent
+ || mLastLaunchedActivity.getWindowingMode() != r.getWindowingMode()) {
+ return false;
+ }
+ // The current task should be non-null because it is just launched. While the
+ // last task can be cleared when starting activity with FLAG_ACTIVITY_CLEAR_TASK.
+ final Task lastTask = mLastLaunchedActivity.getTask();
+ final Task currentTask = r.getTask();
+ if (lastTask != null && currentTask != null) {
+ if (lastTask == currentTask) {
+ return true;
+ }
+ return lastTask.getBounds().equals(currentTask.getBounds());
+ }
+ return mLastLaunchedActivity.isUid(r.launchedFromUid);
}
/** @return {@code true} if the activity matches a launched activity in this transition. */
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f5cb613..c6a2e0e 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2821,6 +2821,27 @@
}
}
+ @Override
+ void waitForSyncTransactionCommit(ArraySet<WindowContainer> wcAwaitingCommit) {
+ super.waitForSyncTransactionCommit(wcAwaitingCommit);
+ if (mStartingData != null) {
+ mStartingData.mWaitForSyncTransactionCommit = true;
+ }
+ }
+
+ @Override
+ void onSyncTransactionCommitted(SurfaceControl.Transaction t) {
+ super.onSyncTransactionCommitted(t);
+ if (mStartingData == null) {
+ return;
+ }
+ mStartingData.mWaitForSyncTransactionCommit = false;
+ if (mStartingData.mRemoveAfterTransaction) {
+ mStartingData.mRemoveAfterTransaction = false;
+ removeStartingWindowAnimation(mStartingData.mPrepareRemoveAnimation);
+ }
+ }
+
void removeStartingWindowAnimation(boolean prepareAnimation) {
mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_IDLE;
if (task != null) {
@@ -2843,6 +2864,12 @@
final WindowState startingWindow = mStartingWindow;
final boolean animate;
if (mStartingData != null) {
+ if (mStartingData.mWaitForSyncTransactionCommit
+ || mTransitionController.inCollectingTransition(startingWindow)) {
+ mStartingData.mRemoveAfterTransaction = true;
+ mStartingData.mPrepareRemoveAnimation = prepareAnimation;
+ return;
+ }
animate = prepareAnimation && mStartingData.needRevealAnimation()
&& mStartingWindow.isVisibleByPolicy();
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Schedule remove starting %s startingWindow=%s"
@@ -2863,18 +2890,7 @@
this);
return;
}
-
- if (animate && mTransitionController.inCollectingTransition(startingWindow)) {
- // Defer remove starting window after transition start.
- // The surface of app window could really show after the transition finish.
- startingWindow.mSyncTransaction.addTransactionCommittedListener(Runnable::run, () -> {
- synchronized (mAtmService.mGlobalLock) {
- surface.remove(true);
- }
- });
- } else {
- surface.remove(animate);
- }
+ surface.remove(animate);
}
/**
@@ -5315,6 +5331,13 @@
if (finishing || isState(STOPPED)) {
displayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
}
+ // Because starting window was transferred, this activity may be a trampoline which has
+ // been occluded by next activity. If it has added windows, set client visibility
+ // immediately to avoid the client getting RELAYOUT_RES_FIRST_TIME from relayout and
+ // drawing an unnecessary frame.
+ if (startingMoved && !firstWindowDrawn && hasChild()) {
+ setClientVisible(false);
+ }
} else {
if (!appTransition.isTransitionSet()
&& appTransition.isReady()) {
diff --git a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
index 5f56af7..1208b6ef 100644
--- a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
+++ b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
@@ -99,13 +99,15 @@
}
public void forEachConnection(Consumer<T> consumer) {
+ final ArraySet<T> connections;
synchronized (mActivity) {
if (mConnections == null || mConnections.isEmpty()) {
return;
}
- for (int i = mConnections.size() - 1; i >= 0; i--) {
- consumer.accept(mConnections.valueAt(i));
- }
+ connections = new ArraySet<>(mConnections);
+ }
+ for (int i = connections.size() - 1; i >= 0; i--) {
+ consumer.accept(connections.valueAt(i));
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index abf66bc..f93afe8 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2008,7 +2008,8 @@
return;
}
- if (r.isState(RESUMED) && r == mRootWindowContainer.getTopResumedActivity()) {
+ if ((touchedActivity == null || r == touchedActivity) && r.isState(RESUMED)
+ && r == mRootWindowContainer.getTopResumedActivity()) {
setLastResumedActivityUncheckLocked(r, "setFocusedTask-alreadyTop");
return;
}
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index 300a894..cff86ad 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -41,6 +41,26 @@
/** Whether the starting window is drawn. */
boolean mIsDisplayed;
+ /**
+ * For Shell transition.
+ * There will be a transition happen on attached activity, do not remove starting window during
+ * this period, because the transaction to show app window may not apply before remove starting
+ * window.
+ * Note this isn't equal to transition playing, the period should be
+ * Sync finishNow -> Start transaction apply.
+ */
+ boolean mWaitForSyncTransactionCommit;
+
+ /**
+ * For Shell transition.
+ * This starting window should be removed after applying the start transaction of transition,
+ * which ensures the app window has shown.
+ */
+ boolean mRemoveAfterTransaction;
+
+ /** Whether to prepare the removal animation. */
+ boolean mPrepareRemoveAnimation;
+
protected StartingData(WindowManagerService service, int typeParams) {
mService = service;
mTypeParams = typeParams;
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index 2e5ab1a..7572a64 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -221,11 +221,11 @@
if (!mAnimationStartDeferred && mPreProcessingAnimations.isEmpty()) {
mChoreographer.postFrameCallback(this::startAnimations);
}
-
- // Some animations (e.g. move animations) require the initial transform to be
- // applied immediately.
- applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
}
+
+ // Some animations (e.g. move animations) require the initial transform to be
+ // applied immediately.
+ applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d1618e9..678d4c8 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -166,6 +166,7 @@
import static com.android.server.wm.WindowStateProto.IS_READY_FOR_DISPLAY;
import static com.android.server.wm.WindowStateProto.IS_VISIBLE;
import static com.android.server.wm.WindowStateProto.KEEP_CLEAR_AREAS;
+import static com.android.server.wm.WindowStateProto.MERGED_LOCAL_INSETS_SOURCES;
import static com.android.server.wm.WindowStateProto.PENDING_SEAMLESS_ROTATION;
import static com.android.server.wm.WindowStateProto.REMOVED;
import static com.android.server.wm.WindowStateProto.REMOVE_ON_EXIT;
@@ -4027,6 +4028,11 @@
for (Rect r : mUnrestrictedKeepClearAreas) {
r.dumpDebug(proto, UNRESTRICTED_KEEP_CLEAR_AREAS);
}
+ if (mMergedLocalInsetsSources != null) {
+ for (int i = 0; i < mMergedLocalInsetsSources.size(); ++i) {
+ mMergedLocalInsetsSources.valueAt(i).dumpDebug(proto, MERGED_LOCAL_INSETS_SOURCES);
+ }
+ }
proto.end(token);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index 702602a..415440b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -632,6 +632,38 @@
}
/**
+ * Returns all the {@code policyKeys} set by any admin that share the same
+ * {@link PolicyKey#getIdentifier()} as the provided {@code policyDefinition}.
+ *
+ * <p>For example, getLocalPolicyKeysSetByAllAdmins(PERMISSION_GRANT) returns all permission
+ * grants set by any admin.
+ *
+ * <p>Note that this will always return at most one item for policies that do not require
+ * additional params (e.g. {@link PolicyDefinition#LOCK_TASK} vs
+ * {@link PolicyDefinition#PERMISSION_GRANT(String, String)}).
+ *
+ */
+ @NonNull
+ <V> Set<PolicyKey> getLocalPolicyKeysSetByAllAdmins(
+ @NonNull PolicyDefinition<V> policyDefinition,
+ int userId) {
+ Objects.requireNonNull(policyDefinition);
+
+ synchronized (mLock) {
+ if (policyDefinition.isGlobalOnlyPolicy() || !mLocalPolicies.contains(userId)) {
+ return Set.of();
+ }
+ Set<PolicyKey> keys = new HashSet<>();
+ for (PolicyKey key : mLocalPolicies.get(userId).keySet()) {
+ if (key.hasSameIdentifierAs(policyDefinition.getPolicyKey())) {
+ keys.add(key);
+ }
+ }
+ return keys;
+ }
+ }
+
+ /**
* Returns all user restriction policies set by the given admin.
*
* <p>Pass in {@link UserHandle#USER_ALL} for {@code userId} to get global restrictions set by
@@ -985,8 +1017,12 @@
int userId = user.id;
// Apply local policies present on parent to newly created child profile.
UserInfo parentInfo = mUserManager.getProfileParent(userId);
- if (parentInfo == null || parentInfo.getUserHandle().getIdentifier() == userId) return;
-
+ if (parentInfo == null || parentInfo.getUserHandle().getIdentifier() == userId) {
+ return;
+ }
+ if (!mLocalPolicies.contains(parentInfo.getUserHandle().getIdentifier())) {
+ return;
+ }
for (Map.Entry<PolicyKey, PolicyState<?>> entry : mLocalPolicies.get(
parentInfo.getUserHandle().getIdentifier()).entrySet()) {
enforcePolicyOnUser(userId, entry.getValue());
@@ -1210,6 +1246,31 @@
synchronized (mLock) {
clear();
new DevicePoliciesReaderWriter().readFromFileLocked();
+ reapplyAllPolicies();
+ }
+ }
+
+ private <V> void reapplyAllPolicies() {
+ for (PolicyKey policy : mGlobalPolicies.keySet()) {
+ PolicyState<?> policyState = mGlobalPolicies.get(policy);
+ // Policy definition and value will always be of the same type
+ PolicyDefinition<V> policyDefinition =
+ (PolicyDefinition<V>) policyState.getPolicyDefinition();
+ PolicyValue<V> policyValue = (PolicyValue<V>) policyState.getCurrentResolvedPolicy();
+ enforcePolicy(policyDefinition, policyValue, UserHandle.USER_ALL);
+ }
+ for (int i = 0; i < mLocalPolicies.size(); i++) {
+ int userId = mLocalPolicies.keyAt(i);
+ for (PolicyKey policy : mLocalPolicies.get(userId).keySet()) {
+ PolicyState<?> policyState = mLocalPolicies.get(userId).get(policy);
+ // Policy definition and value will always be of the same type
+ PolicyDefinition<V> policyDefinition =
+ (PolicyDefinition<V>) policyState.getPolicyDefinition();
+ PolicyValue<V> policyValue =
+ (PolicyValue<V>) policyState.getCurrentResolvedPolicy();
+ enforcePolicy(policyDefinition, policyValue, userId);
+
+ }
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8557348..18fcafa 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -85,6 +85,7 @@
import static android.Manifest.permission.SET_TIME;
import static android.Manifest.permission.SET_TIME_ZONE;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
+import static android.accounts.AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
@@ -280,6 +281,7 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
+import android.app.admin.AccountTypePolicyKey;
import android.app.admin.BooleanPolicyValue;
import android.app.admin.BundlePolicyValue;
import android.app.admin.ComponentNamePolicyValue;
@@ -531,6 +533,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -1139,6 +1142,11 @@
}
}
}
+
+ if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+ calculateHasIncompatibleAccounts();
+ }
+
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
&& userHandle == mOwners.getDeviceOwnerUserId()) {
mBugreportCollectionManager.checkForPendingBugreportAfterBoot();
@@ -1252,6 +1260,8 @@
} else if (ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)) {
notifyIfManagedSubscriptionsAreUnavailable(
UserHandle.of(userHandle), /* managedProfileAvailable= */ true);
+ } else if (LOGIN_ACCOUNTS_CHANGED_ACTION.equals(action)) {
+ calculateHasIncompatibleAccounts();
}
}
@@ -2104,6 +2114,7 @@
filter.addAction(Intent.ACTION_USER_STOPPED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
+ filter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION);
filter.addAction(ACTION_MANAGED_PROFILE_UNAVAILABLE);
filter.addAction(ACTION_MANAGED_PROFILE_AVAILABLE);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
@@ -2130,7 +2141,7 @@
mUserManagerInternal.addUserLifecycleListener(new UserLifecycleListener());
mDeviceManagementResourcesProvider.load();
- if (isPermissionCheckFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled() || isPolicyEngineForFinanceFlagEnabled()) {
mDevicePolicyEngine.load();
}
@@ -3279,8 +3290,10 @@
policy.validatePasswordOwner();
updateMaximumTimeToLockLocked(userHandle);
- updateLockTaskPackagesLocked(mContext, policy.mLockTaskPackages, userHandle);
- updateLockTaskFeaturesLocked(policy.mLockTaskFeatures, userHandle);
+ if (!isPolicyEngineForFinanceFlagEnabled()) {
+ updateLockTaskPackagesLocked(mContext, policy.mLockTaskPackages, userHandle);
+ updateLockTaskFeaturesLocked(policy.mLockTaskFeatures, userHandle);
+ }
if (policy.mStatusBarDisabled) {
setStatusBarDisabledInternal(policy.mStatusBarDisabled, userHandle);
}
@@ -3592,7 +3605,7 @@
}
startOwnerService(userId, "start-user");
- if (isPermissionCheckFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled() || isPolicyEngineForFinanceFlagEnabled()) {
mDevicePolicyEngine.handleStartUser(userId);
}
}
@@ -3619,7 +3632,7 @@
void handleUnlockUser(int userId) {
startOwnerService(userId, "unlock-user");
- if (isPermissionCheckFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled() || isPolicyEngineForFinanceFlagEnabled()) {
mDevicePolicyEngine.handleUnlockUser(userId);
}
}
@@ -3631,7 +3644,7 @@
void handleStopUser(int userId) {
updateNetworkPreferenceForUser(userId, List.of(PreferentialNetworkServiceConfig.DEFAULT));
mDeviceAdminServiceController.stopServicesForUser(userId, /* actionForLog= */ "stop-user");
- if (isPermissionCheckFlagEnabled()) {
+ if (isPermissionCheckFlagEnabled() || isPolicyEngineForFinanceFlagEnabled()) {
mDevicePolicyEngine.handleStopUser(userId);
}
}
@@ -9557,6 +9570,7 @@
synchronized (getLockObject()) {
enforceCanSetDeviceOwnerLocked(caller, admin, userId, hasIncompatibleAccountsOrNonAdb);
+
Preconditions.checkArgument(isPackageInstalledForUser(admin.getPackageName(), userId),
"Invalid component " + admin + " for device owner");
final ActiveAdmin activeAdmin = getActiveAdminUncheckedLocked(admin, userId);
@@ -10246,7 +10260,9 @@
policy.mUserProvisioningState = DevicePolicyManager.STATE_USER_UNMANAGED;
policy.mAffiliationIds.clear();
policy.mLockTaskPackages.clear();
- updateLockTaskPackagesLocked(mContext, policy.mLockTaskPackages, userId);
+ if (!isPolicyEngineForFinanceFlagEnabled()) {
+ updateLockTaskPackagesLocked(mContext, policy.mLockTaskPackages, userId);
+ }
policy.mLockTaskFeatures = DevicePolicyManager.LOCK_TASK_FEATURE_NONE;
saveSettingsLocked(userId);
@@ -11036,7 +11052,7 @@
return false;
}
- if (!isPermissionCheckFlagEnabled()) {
+ if (!isPermissionCheckFlagEnabled() && !isPolicyEngineForFinanceFlagEnabled()) {
// TODO: Figure out if something like this needs to be restored for policy engine
final ComponentName profileOwner = getProfileOwnerAsUser(userId);
if (profileOwner == null) {
@@ -11051,17 +11067,6 @@
return true;
}
-
- private void enforceCanCallLockTaskLocked(CallerIdentity caller) {
- Preconditions.checkCallAuthorization(isProfileOwner(caller)
- || isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
-
- final int userId = caller.getUserId();
- if (!canUserUseLockTaskLocked(userId)) {
- throw new SecurityException("User " + userId + " is not allowed to use lock task");
- }
- }
-
private void enforceCanQueryLockTaskLocked(ComponentName who, String callerPackageName) {
CallerIdentity caller = getCallerIdentity(who, callerPackageName);
final int userId = caller.getUserId();
@@ -11089,6 +11094,16 @@
return enforcingAdmin;
}
+ private void enforceCanCallLockTaskLocked(CallerIdentity caller) {
+ Preconditions.checkCallAuthorization(isProfileOwner(caller)
+ || isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
+
+ final int userId = caller.getUserId();
+ if (!canUserUseLockTaskLocked(userId)) {
+ throw new SecurityException("User " + userId + " is not allowed to use lock task");
+ }
+ }
+
private boolean isSystemUid(CallerIdentity caller) {
return UserHandle.isSameApp(caller.getUid(), Process.SYSTEM_UID);
}
@@ -14020,16 +14035,28 @@
caller = getCallerIdentity(who);
}
synchronized (getLockObject()) {
- final ActiveAdmin ap;
if (isPermissionCheckFlagEnabled()) {
+ int affectedUser = getAffectedUser(parent);
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
caller.getPackageName(),
- getAffectedUser(parent)
+ affectedUser
);
- ap = enforcingAdmin.getActiveAdmin();
+ if (disabled) {
+ mDevicePolicyEngine.setLocalPolicy(
+ PolicyDefinition.ACCOUNT_MANAGEMENT_DISABLED(accountType),
+ enforcingAdmin,
+ new BooleanPolicyValue(disabled),
+ affectedUser);
+ } else {
+ mDevicePolicyEngine.removeLocalPolicy(
+ PolicyDefinition.ACCOUNT_MANAGEMENT_DISABLED(accountType),
+ enforcingAdmin,
+ affectedUser);
+ }
} else {
+ final ActiveAdmin ap;
Objects.requireNonNull(who, "ComponentName is null");
/*
* When called on the parent DPM instance (parent == true), affects active admin
@@ -14046,13 +14073,13 @@
ap = getParentOfAdminIfRequired(
getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), parent);
}
+ if (disabled) {
+ ap.accountTypesWithManagementDisabled.add(accountType);
+ } else {
+ ap.accountTypesWithManagementDisabled.remove(accountType);
+ }
+ saveSettingsLocked(UserHandle.getCallingUserId());
}
- if (disabled) {
- ap.accountTypesWithManagementDisabled.add(accountType);
- } else {
- ap.accountTypesWithManagementDisabled.remove(accountType);
- }
- saveSettingsLocked(UserHandle.getCallingUserId());
}
}
@@ -14070,41 +14097,64 @@
}
CallerIdentity caller;
Preconditions.checkArgumentNonnegative(userId, "Invalid userId");
+ final ArraySet<String> resultSet = new ArraySet<>();
if (isPermissionCheckFlagEnabled()) {
+ int affectedUser = parent ? getProfileParentId(userId) : userId;
caller = getCallerIdentity(callerPackageName);
if (!hasPermission(MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
- caller.getPackageName(), userId)
+ callerPackageName, affectedUser)
&& !hasFullCrossUsersPermission(caller, userId)) {
throw new SecurityException("Caller does not have permission to call this on user: "
- + userId);
+ + affectedUser);
}
- } else {
- caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userId));
- }
+ Set<PolicyKey> keys = mDevicePolicyEngine.getLocalPolicyKeysSetByAllAdmins(
+ PolicyDefinition.GENERIC_ACCOUNT_MANAGEMENT_DISABLED,
+ affectedUser);
- synchronized (getLockObject()) {
- final ArraySet<String> resultSet = new ArraySet<>();
+ for (PolicyKey key : keys) {
+ if (!(key instanceof AccountTypePolicyKey)) {
+ throw new IllegalStateException("PolicyKey for "
+ + "MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT is not of type "
+ + "AccountTypePolicyKey");
+ }
+ AccountTypePolicyKey parsedKey =
+ (AccountTypePolicyKey) key;
+ String accountType = Objects.requireNonNull(parsedKey.getAccountType());
- if (!parent) {
- final DevicePolicyData policy = getUserData(userId);
- for (ActiveAdmin admin : policy.mAdminList) {
- resultSet.addAll(admin.accountTypesWithManagementDisabled);
+ Boolean disabled = mDevicePolicyEngine.getResolvedPolicy(
+ PolicyDefinition.ACCOUNT_MANAGEMENT_DISABLED(accountType),
+ affectedUser);
+ if (disabled != null && disabled) {
+ resultSet.add(accountType);
}
}
- // Check if there's a profile owner of an org-owned device and the method is called for
- // the parent user of this profile owner.
- final ActiveAdmin orgOwnedAdmin =
- getProfileOwnerOfOrganizationOwnedDeviceLocked(userId);
- final boolean shouldGetParentAccounts = orgOwnedAdmin != null && (parent
- || UserHandle.getUserId(orgOwnedAdmin.getUid()) != userId);
- if (shouldGetParentAccounts) {
- resultSet.addAll(
- orgOwnedAdmin.getParentActiveAdmin().accountTypesWithManagementDisabled);
+ } else {
+ caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userId));
+
+ synchronized (getLockObject()) {
+ if (!parent) {
+ final DevicePolicyData policy = getUserData(userId);
+ for (ActiveAdmin admin : policy.mAdminList) {
+ resultSet.addAll(admin.accountTypesWithManagementDisabled);
+ }
+ }
+
+ // Check if there's a profile owner of an org-owned device and the method is called
+ // for the parent user of this profile owner.
+ final ActiveAdmin orgOwnedAdmin =
+ getProfileOwnerOfOrganizationOwnedDeviceLocked(userId);
+ final boolean shouldGetParentAccounts = orgOwnedAdmin != null && (parent
+ || UserHandle.getUserId(orgOwnedAdmin.getUid()) != userId);
+ if (shouldGetParentAccounts) {
+ resultSet.addAll(
+ orgOwnedAdmin.getParentActiveAdmin()
+ .accountTypesWithManagementDisabled);
+ }
}
- return resultSet.toArray(new String[resultSet.size()]);
}
+ return resultSet.toArray(new String[resultSet.size()]);
}
@Override
@@ -14679,7 +14729,7 @@
if (isPolicyEngineForFinanceFlagEnabled()) {
EnforcingAdmin enforcingAdmin;
synchronized (getLockObject()) {
- enforcingAdmin = enforceCanCallLockTaskLocked(who, callerPackageName);
+ enforcingAdmin = enforceCanCallLockTaskLocked(who, caller.getPackageName());
}
if (packages.length == 0) {
mDevicePolicyEngine.removeLocalPolicy(
@@ -14806,8 +14856,7 @@
if (isPolicyEngineForFinanceFlagEnabled()) {
EnforcingAdmin enforcingAdmin;
synchronized (getLockObject()) {
- enforcingAdmin = enforceCanCallLockTaskLocked(who,
- callerPackageName);
+ enforcingAdmin = enforceCanCallLockTaskLocked(who, caller.getPackageName());
enforceCanSetLockTaskFeaturesOnFinancedDevice(caller, flags);
}
LockTaskPolicy currentPolicy = mDevicePolicyEngine.getLocalPolicySetByAdmin(
@@ -14884,6 +14933,7 @@
}
final List<String> lockTaskPackages = getUserData(userId).mLockTaskPackages;
+ // TODO(b/278438525): handle in the policy engine
if (!lockTaskPackages.isEmpty()) {
Slogf.d(LOG_TAG,
"User id " + userId + " not affiliated. Clearing lock task packages");
@@ -18347,6 +18397,26 @@
return isUserAffiliatedWithDeviceLocked(userId);
}
+ private boolean hasIncompatibleAccountsOnAnyUser() {
+ if (mHasIncompatibleAccounts == null) {
+ // Hasn't loaded for the first time yet - assume the worst
+ return true;
+ }
+
+ for (boolean hasIncompatible : mHasIncompatibleAccounts.values()) {
+ if (hasIncompatible) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private boolean hasIncompatibleAccounts(int userId) {
+ return mHasIncompatibleAccounts == null ? true
+ : mHasIncompatibleAccounts.getOrDefault(userId, /* default= */ false);
+ }
+
/**
* Return true if a given user has any accounts that'll prevent installing a device or profile
* owner {@code owner}.
@@ -18384,7 +18454,7 @@
}
}
- boolean compatible = !hasIncompatibleAccounts(am, accounts);
+ boolean compatible = !hasIncompatibleAccounts(userId);
if (compatible) {
Slogf.w(LOG_TAG, "All accounts are compatible");
} else {
@@ -18394,37 +18464,67 @@
});
}
- private boolean hasIncompatibleAccounts(AccountManager am, Account[] accounts) {
- // TODO(b/244284408): Add test
- final String[] feature_allow =
- { DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED };
- final String[] feature_disallow =
- { DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED };
-
- for (Account account : accounts) {
- if (hasAccountFeatures(am, account, feature_disallow)) {
- Slogf.e(LOG_TAG, "%s has %s", account, feature_disallow[0]);
- return true;
- }
- if (!hasAccountFeatures(am, account, feature_allow)) {
- Slogf.e(LOG_TAG, "%s doesn't have %s", account, feature_allow[0]);
- return true;
- }
- }
-
- return false;
+ @Override
+ public void calculateHasIncompatibleAccounts() {
+ new CalculateHasIncompatibleAccountsTask().executeOnExecutor(
+ AsyncTask.THREAD_POOL_EXECUTOR, null);
}
- private boolean hasAccountFeatures(AccountManager am, Account account, String[] features) {
- try {
- // TODO(267156507): Restore without blocking binder thread
- return false;
-// return am.hasFeatures(account, features, null, null).getResult();
- } catch (Exception e) {
- Slogf.w(LOG_TAG, "Failed to get account feature", e);
+ @Nullable
+ private volatile Map<Integer, Boolean> mHasIncompatibleAccounts;
+
+ class CalculateHasIncompatibleAccountsTask extends AsyncTask<
+ Void, Void, Map<Integer, Boolean>> {
+ private static final String[] FEATURE_ALLOW =
+ {DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED};
+ private static final String[] FEATURE_DISALLOW =
+ {DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED};
+
+ @Override
+ protected Map<Integer, Boolean> doInBackground(Void... args) {
+ List<UserInfo> users = mUserManagerInternal.getUsers(/* excludeDying= */ true);
+ Map<Integer, Boolean> results = new HashMap<>();
+ for (UserInfo userInfo : users) {
+ results.put(userInfo.id, userHasIncompatibleAccounts(userInfo.id));
+ }
+
+ return results;
+ }
+
+ private boolean userHasIncompatibleAccounts(int id) {
+ AccountManager am = mContext.createContextAsUser(UserHandle.of(id), /* flags= */ 0)
+ .getSystemService(AccountManager.class);
+ Account[] accounts = am.getAccounts();
+
+ for (Account account : accounts) {
+ if (hasAccountFeatures(am, account, FEATURE_DISALLOW)) {
+ return true;
+ }
+ if (!hasAccountFeatures(am, account, FEATURE_ALLOW)) {
+ return true;
+ }
+ }
+
return false;
}
- }
+
+ @Override
+ protected void onPostExecute(Map<Integer, Boolean> results) {
+ mHasIncompatibleAccounts = Collections.unmodifiableMap(results);
+
+ Slogf.i(LOG_TAG, "Finished calculating hasIncompatibleAccountsTask");
+ }
+
+ private static boolean hasAccountFeatures(AccountManager am, Account account,
+ String[] features) {
+ try {
+ return am.hasFeatures(account, features, null, null).getResult();
+ } catch (Exception e) {
+ Slogf.w(LOG_TAG, "Failed to get account feature", e);
+ return false;
+ }
+ }
+ };
private boolean isAdb(CallerIdentity caller) {
return isShellUid(caller) || isRootUid(caller);
@@ -22256,26 +22356,6 @@
}
}
- private boolean hasIncompatibleAccountsOnAnyUser() {
- long callingIdentity = Binder.clearCallingIdentity();
- try {
- for (UserInfo user : mUserManagerInternal.getUsers(/* excludeDying= */ true)) {
- AccountManager am = mContext.createContextAsUser(
- UserHandle.of(user.id), /* flags= */ 0)
- .getSystemService(AccountManager.class);
- Account[] accounts = am.getAccounts();
-
- if (hasIncompatibleAccounts(am, accounts)) {
- return true;
- }
- }
-
- return false;
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
- }
-
private void setBypassDevicePolicyManagementRoleQualificationStateInternal(
String currentRoleHolder, boolean allowBypass) {
boolean stateChanged = false;
@@ -22516,11 +22596,26 @@
"manage_device_policy_microphone_toggle";
// DPC types
+ private static final int NOT_A_DPC = -1;
private static final int DEFAULT_DEVICE_OWNER = 0;
private static final int FINANCED_DEVICE_OWNER = 1;
private static final int PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE = 2;
private static final int PROFILE_OWNER_ON_USER_0 = 3;
private static final int PROFILE_OWNER = 4;
+ private static final int PROFILE_OWNER_ON_USER = 5;
+ private static final int AFFILIATED_PROFILE_OWNER_ON_USER = 6;
+ // DPC types
+ @IntDef(value = {
+ NOT_A_DPC,
+ DEFAULT_DEVICE_OWNER,
+ FINANCED_DEVICE_OWNER,
+ PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE,
+ PROFILE_OWNER_ON_USER_0,
+ PROFILE_OWNER,
+ PROFILE_OWNER_ON_USER,
+ AFFILIATED_PROFILE_OWNER_ON_USER
+ })
+ private @interface DpcType {}
// Permissions of existing DPC types.
private static final List<String> DEFAULT_DEVICE_OWNER_PERMISSIONS = List.of(
@@ -22674,7 +22769,9 @@
SET_TIME_ZONE
);
-
+ /**
+ * All the additional permissions granted to a Profile Owner on user 0.
+ */
private static final List<String> ADDITIONAL_PROFILE_OWNER_ON_USER_0_PERMISSIONS =
List.of(
MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
@@ -22699,6 +22796,20 @@
);
/**
+ * All the additional permissions granted to a Profile Owner on an unaffiliated user.
+ */
+ private static final List<String> ADDITIONAL_PROFILE_OWNER_ON_USER_PERMISSIONS =
+ List.of(
+ MANAGE_DEVICE_POLICY_LOCK_TASK
+ );
+
+ /**
+ * All the additional permissions granted to a Profile Owner on an affiliated user.
+ */
+ private static final List<String> ADDITIONAL_AFFILIATED_PROFILE_OWNER_ON_USER_PERMISSIONS =
+ List.of();
+
+ /**
* Combination of {@link PROFILE_OWNER_PERMISSIONS} and
* {@link ADDITIONAL_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS}.
*/
@@ -22712,6 +22823,20 @@
private static final List<String> PROFILE_OWNER_ON_USER_0_PERMISSIONS =
new ArrayList();
+ /**
+ * Combination of {@link PROFILE_OWNER_PERMISSIONS} and
+ * {@link ADDITIONAL_AFFILIATED_PROFIL_OWNER_ON_USER_PERMISSIONS}.
+ */
+ private static final List<String> AFFILIATED_PROFILE_OWNER_ON_USER_PERMISSIONS =
+ new ArrayList();
+
+ /**
+ * Combination of {@link PROFILE_OWNER_PERMISSIONS} and
+ * {@link ADDITIONAL_PROFILE_OWNER_ON_USER_PERMISSIONS}.
+ */
+ private static final List<String> PROFILE_OWNER_ON_USER_PERMISSIONS =
+ new ArrayList();
+
private static final HashMap<Integer, List<String>> DPC_PERMISSIONS = new HashMap<>();
{
@@ -22724,6 +22849,16 @@
// some extra permissions.
PROFILE_OWNER_ON_USER_0_PERMISSIONS.addAll(PROFILE_OWNER_PERMISSIONS);
PROFILE_OWNER_ON_USER_0_PERMISSIONS.addAll(ADDITIONAL_PROFILE_OWNER_ON_USER_0_PERMISSIONS);
+ // Profile owners on users have all the permission of a profile owner plus
+ // some extra permissions.
+ PROFILE_OWNER_ON_USER_PERMISSIONS.addAll(PROFILE_OWNER_PERMISSIONS);
+ PROFILE_OWNER_ON_USER_PERMISSIONS.addAll(
+ ADDITIONAL_PROFILE_OWNER_ON_USER_PERMISSIONS);
+ // Profile owners on affiliated users have all the permission of a profile owner on a user
+ // plus some extra permissions.
+ AFFILIATED_PROFILE_OWNER_ON_USER_PERMISSIONS.addAll(PROFILE_OWNER_ON_USER_PERMISSIONS);
+ AFFILIATED_PROFILE_OWNER_ON_USER_PERMISSIONS.addAll(
+ ADDITIONAL_AFFILIATED_PROFILE_OWNER_ON_USER_PERMISSIONS);
DPC_PERMISSIONS.put(DEFAULT_DEVICE_OWNER, DEFAULT_DEVICE_OWNER_PERMISSIONS);
DPC_PERMISSIONS.put(FINANCED_DEVICE_OWNER, FINANCED_DEVICE_OWNER_PERMISSIONS);
@@ -22731,6 +22866,9 @@
PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS);
DPC_PERMISSIONS.put(PROFILE_OWNER_ON_USER_0, PROFILE_OWNER_ON_USER_0_PERMISSIONS);
DPC_PERMISSIONS.put(PROFILE_OWNER, PROFILE_OWNER_PERMISSIONS);
+ DPC_PERMISSIONS.put(PROFILE_OWNER_ON_USER, PROFILE_OWNER_ON_USER_PERMISSIONS);
+ DPC_PERMISSIONS.put(AFFILIATED_PROFILE_OWNER_ON_USER,
+ AFFILIATED_PROFILE_OWNER_ON_USER_PERMISSIONS);
}
//Map of Permission to Delegate Scope.
private static final HashMap<String, String> DELEGATE_SCOPES = new HashMap<>();
@@ -23108,22 +23246,9 @@
if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
return true;
}
- // Check the permissions of DPCs
- if (isDefaultDeviceOwner(caller)) {
- return DPC_PERMISSIONS.get(DEFAULT_DEVICE_OWNER).contains(permission);
- }
- if (isFinancedDeviceOwner(caller)) {
- return DPC_PERMISSIONS.get(FINANCED_DEVICE_OWNER).contains(permission);
- }
- if (isProfileOwnerOfOrganizationOwnedDevice(caller)) {
- return DPC_PERMISSIONS.get(PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE).contains(
- permission);
- }
- if (isProfileOwnerOnUser0(caller)) {
- return DPC_PERMISSIONS.get(PROFILE_OWNER_ON_USER_0).contains(permission);
- }
- if (isProfileOwner(caller)) {
- return DPC_PERMISSIONS.get(PROFILE_OWNER).contains(permission);
+ int dpcType = getDpcType(caller);
+ if (dpcType != NOT_A_DPC) {
+ return DPC_PERMISSIONS.get(dpcType).contains(permission);
}
// Check the permission for the role-holder
if (isCallerDevicePolicyManagementRoleHolder(caller)) {
@@ -23193,6 +23318,35 @@
return calledOnParent ? getProfileParentId(callingUserId) : callingUserId;
}
+ /**
+ * Return the DPC type of the given caller.
+ */
+ private @DpcType int getDpcType(CallerIdentity caller) {
+ // Check the permissions of DPCs
+ if (isDefaultDeviceOwner(caller)) {
+ return DEFAULT_DEVICE_OWNER;
+ }
+ if (isFinancedDeviceOwner(caller)) {
+ return FINANCED_DEVICE_OWNER;
+ }
+ if (isProfileOwner(caller)) {
+ if (isProfileOwnerOfOrganizationOwnedDevice(caller)) {
+ return PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE;
+ }
+ if (isManagedProfile(caller.getUserId())) {
+ return PROFILE_OWNER;
+ }
+ if (isProfileOwnerOnUser0(caller)) {
+ return PROFILE_OWNER_ON_USER_0;
+ }
+ if (isUserAffiliatedWithDevice(caller.getUserId())) {
+ return AFFILIATED_PROFILE_OWNER_ON_USER;
+ }
+ return PROFILE_OWNER_ON_USER;
+ }
+ return NOT_A_DPC;
+ }
+
private boolean isPermissionCheckFlagEnabled() {
return DeviceConfig.getBoolean(
NAMESPACE_DEVICE_POLICY_MANAGER,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 8c2468a..638596b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.admin.AccountTypePolicyKey;
import android.app.admin.BooleanPolicyValue;
import android.app.admin.DevicePolicyIdentifiers;
import android.app.admin.DevicePolicyManager;
@@ -281,6 +282,32 @@
DevicePolicyIdentifiers.APPLICATION_HIDDEN_POLICY, packageName));
}
+ // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
+ // actual policy with the correct arguments (i.e. packageName) when reading the policies from
+ // xml.
+ static PolicyDefinition<Boolean> GENERIC_ACCOUNT_MANAGEMENT_DISABLED =
+ new PolicyDefinition<>(
+ new AccountTypePolicyKey(
+ DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY),
+ TRUE_MORE_RESTRICTIVE,
+ POLICY_FLAG_LOCAL_ONLY_POLICY,
+ // Nothing is enforced, we just need to store it
+ (Boolean value, Context context, Integer userId, PolicyKey policyKey) -> true,
+ new BooleanPolicySerializer());
+
+ /**
+ * Passing in {@code null} for {@code accountType} will return
+ * {@link #GENERIC_ACCOUNT_MANAGEMENT_DISABLED}.
+ */
+ static PolicyDefinition<Boolean> ACCOUNT_MANAGEMENT_DISABLED(String accountType) {
+ if (accountType == null) {
+ return GENERIC_ACCOUNT_MANAGEMENT_DISABLED;
+ }
+ return GENERIC_ACCOUNT_MANAGEMENT_DISABLED.createPolicyDefinition(
+ new AccountTypePolicyKey(
+ DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY, accountType));
+ }
+
private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>();
private static Map<String, Integer> USER_RESTRICTION_FLAGS = new HashMap<>();
@@ -304,6 +331,8 @@
KEYGUARD_DISABLED_FEATURES);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.APPLICATION_HIDDEN_POLICY,
GENERIC_APPLICATION_HIDDEN);
+ POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY,
+ GENERIC_ACCOUNT_MANAGEMENT_DISABLED);
// User Restriction Policies
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MODIFY_ACCOUNTS, /* flags= */ 0);
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
index 8c84014..dc92376 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
@@ -199,10 +199,11 @@
}
public Intent getResult() {
- try {
- return mResult.take();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
+ while (true) {
+ try {
+ return mResult.take();
+ } catch (InterruptedException e) {
+ }
}
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/HighBrightnessModeMetadataMapperTest.java b/services/tests/mockingservicestests/src/com/android/server/display/HighBrightnessModeMetadataMapperTest.java
new file mode 100644
index 0000000..d9fbba5
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/display/HighBrightnessModeMetadataMapperTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 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.server.display;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class HighBrightnessModeMetadataMapperTest {
+
+ private HighBrightnessModeMetadataMapper mHighBrightnessModeMetadataMapper;
+
+ @Before
+ public void setUp() {
+ mHighBrightnessModeMetadataMapper = new HighBrightnessModeMetadataMapper();
+ }
+
+ @Test
+ public void testGetHighBrightnessModeMetadata() {
+ // Display device is null
+ final LogicalDisplay display = mock(LogicalDisplay.class);
+ when(display.getPrimaryDisplayDeviceLocked()).thenReturn(null);
+ assertNull(mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display));
+
+ // No HBM metadata stored for this display yet
+ final DisplayDevice device = mock(DisplayDevice.class);
+ when(display.getPrimaryDisplayDeviceLocked()).thenReturn(device);
+ HighBrightnessModeMetadata hbmMetadata =
+ mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display);
+ assertTrue(hbmMetadata.getHbmEventQueue().isEmpty());
+ assertTrue(hbmMetadata.getRunningStartTimeMillis() < 0);
+
+ // Modify the metadata
+ long startTimeMillis = 100;
+ long endTimeMillis = 200;
+ long setTime = 300;
+ hbmMetadata.addHbmEvent(new HbmEvent(startTimeMillis, endTimeMillis));
+ hbmMetadata.setRunningStartTimeMillis(setTime);
+ hbmMetadata =
+ mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display);
+ assertEquals(1, hbmMetadata.getHbmEventQueue().size());
+ assertEquals(startTimeMillis,
+ hbmMetadata.getHbmEventQueue().getFirst().getStartTimeMillis());
+ assertEquals(endTimeMillis, hbmMetadata.getHbmEventQueue().getFirst().getEndTimeMillis());
+ assertEquals(setTime, hbmMetadata.getRunningStartTimeMillis());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index 913d8c1..11e4120 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -35,6 +35,7 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -435,9 +436,9 @@
mMockConnection.invokeCallbacks();
assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
- verify(mScreenMagnificationController).setScaleAndCenter(TEST_DISPLAY,
- DEFAULT_SCALE, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y,
- animate, TEST_SERVICE_ID);
+ verify(mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY),
+ eq(DEFAULT_SCALE), eq(MAGNIFIED_CENTER_X), eq(MAGNIFIED_CENTER_Y),
+ any(MagnificationAnimationCallback.class), eq(TEST_SERVICE_ID));
}
@Test
@@ -504,6 +505,42 @@
}
@Test
+ public void configTransitionToFullScreenWithAnimation_windowMagnifying_notifyService()
+ throws RemoteException {
+ final boolean animate = true;
+ activateMagnifier(MODE_WINDOW, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
+
+ reset(mService);
+ MagnificationConfig config = (new MagnificationConfig.Builder())
+ .setMode(MODE_FULLSCREEN).build();
+ mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
+ config, animate, TEST_SERVICE_ID);
+ verify(mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY),
+ /* scale= */ anyFloat(), /* centerX= */ anyFloat(), /* centerY= */ anyFloat(),
+ mCallbackArgumentCaptor.capture(), /* id= */ anyInt());
+ mCallbackArgumentCaptor.getValue().onResult(true);
+ mMockConnection.invokeCallbacks();
+
+ verify(mService).changeMagnificationMode(TEST_DISPLAY, MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void configTransitionToFullScreenWithoutAnimation_windowMagnifying_notifyService()
+ throws RemoteException {
+ final boolean animate = false;
+ activateMagnifier(MODE_WINDOW, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
+
+ reset(mService);
+ MagnificationConfig config = (new MagnificationConfig.Builder())
+ .setMode(MODE_FULLSCREEN).build();
+ mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
+ config, animate, TEST_SERVICE_ID);
+ mMockConnection.invokeCallbacks();
+
+ verify(mService).changeMagnificationMode(TEST_DISPLAY, MODE_FULLSCREEN);
+ }
+
+ @Test
public void interruptDuringTransitionToWindow_disablingFullScreen_discardPreviousTransition()
throws RemoteException {
activateMagnifier(MODE_FULLSCREEN, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 4e001fe..37c4b37 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -28,6 +28,7 @@
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
@@ -501,6 +502,12 @@
onActivityLaunched(mTrampolineActivity);
mActivityMetricsLogger.notifyActivityLaunching(mTopActivity.intent,
mTrampolineActivity /* caller */, mTrampolineActivity.getUid());
+
+ // Simulate a corner case that the trampoline activity is removed by CLEAR_TASK.
+ // The 2 launch events can still be coalesced to one by matching the uid.
+ mTrampolineActivity.takeFromHistory();
+ assertNull(mTrampolineActivity.getTask());
+
notifyActivityLaunched(START_SUCCESS, mTopActivity);
transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 8f2b470..0033e3e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2399,7 +2399,10 @@
holder.addConnection(connection);
assertTrue(holder.isActivityVisible());
final int[] count = new int[1];
- final Consumer<Object> c = conn -> count[0]++;
+ final Consumer<Object> c = conn -> {
+ count[0]++;
+ assertFalse(Thread.holdsLock(activity));
+ };
holder.forEachConnection(c);
assertEquals(1, count[0]);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 49d8da1..9d597b1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -586,6 +586,15 @@
// Making the activity0 be the focused activity and ensure the focused app is updated.
activity0.moveFocusableActivityToTop("test");
assertEquals(activity0, mDisplayContent.mFocusedApp);
+
+ // Moving activity1 to top and make both the two activities resumed.
+ activity1.moveFocusableActivityToTop("test");
+ activity0.setState(RESUMED, "test");
+ activity1.setState(RESUMED, "test");
+
+ // Verifies that the focus app can be updated to an Activity in the adjacent TF
+ mAtm.setFocusedTask(task.mTaskId, activity0);
+ assertEquals(activity0, mDisplayContent.mFocusedApp);
}
@Test
diff --git a/telephony/OWNERS b/telephony/OWNERS
index 025869d..3158ad8 100644
--- a/telephony/OWNERS
+++ b/telephony/OWNERS
@@ -11,12 +11,6 @@
[email protected]
[email protected]
-# Temporarily reduced the owner during refactoring
-per-file SubscriptionManager.java=set noparent
-per-file [email protected],[email protected]
-per-file SubscriptionInfo.java=set noparent
-per-file [email protected],[email protected]
-
# Requiring TL ownership for new carrier config keys.
per-file CarrierConfigManager.java=set noparent
per-file [email protected],[email protected],[email protected],[email protected]
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 905a90c..caafce2 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -331,8 +331,8 @@
* Same as {@link #checkCallingOrSelfReadSubscriberIdentifiers(Context, int, String, String,
* String)} except this allows an additional parameter reportFailure. Caller may not want to
* report a failure when this is an internal/intermediate check, for example,
- * SubscriptionController calls this with an INVALID_SUBID to check if caller has the required
- * permissions to bypass carrier privilege checks.
+ * SubscriptionManagerService calls this with an INVALID_SUBID to check if caller has the
+ * required permissions to bypass carrier privilege checks.
* @param reportFailure Indicates if failure should be reported.
*/
public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 559faf9..64e4356 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -91,8 +91,7 @@
import java.util.stream.Collectors;
/**
- * SubscriptionManager is the application interface to SubscriptionController
- * and provides information about the current Telephony Subscriptions.
+ * Subscription manager provides the mobile subscription information.
*/
@SystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
@@ -119,13 +118,12 @@
public static final int DEFAULT_SUBSCRIPTION_ID = Integer.MAX_VALUE;
/**
- * Indicates the caller wants the default phone id.
- * Used in SubscriptionController and Phone but do we really need it???
+ * Indicates the default phone id.
* @hide
*/
public static final int DEFAULT_PHONE_INDEX = Integer.MAX_VALUE;
- /** Indicates the caller wants the default slot id. NOT used remove? */
+ /** Indicates the default slot index. */
/** @hide */
public static final int DEFAULT_SIM_SLOT_INDEX = Integer.MAX_VALUE;
@@ -141,29 +139,10 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final Uri CONTENT_URI = SimInfo.CONTENT_URI;
- private static final String CACHE_KEY_DEFAULT_SUB_ID_PROPERTY =
- "cache_key.telephony.get_default_sub_id";
-
- private static final String CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY =
- "cache_key.telephony.get_default_data_sub_id";
-
- private static final String CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY =
- "cache_key.telephony.get_default_sms_sub_id";
-
- private static final String CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY =
- "cache_key.telephony.get_active_data_sub_id";
-
- private static final String CACHE_KEY_SLOT_INDEX_PROPERTY =
- "cache_key.telephony.get_slot_index";
-
/** The IPC cache key shared by all subscription manager service cacheable properties. */
private static final String CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY =
"cache_key.telephony.subscription_manager_service";
- /** The temporarily cache key to indicate whether subscription manager service is enabled. */
- private static final String CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_ENABLED_PROPERTY =
- "cache_key.telephony.subscription_manager_service_enabled";
-
/** @hide */
public static final String GET_SIM_SPECIFIC_SETTINGS_METHOD_NAME = "getSimSpecificSettings";
@@ -273,83 +252,41 @@
}
}
- private static VoidPropertyInvalidatedCache<Integer> sDefaultSubIdCache =
- new VoidPropertyInvalidatedCache<>(ISub::getDefaultSubId,
- CACHE_KEY_DEFAULT_SUB_ID_PROPERTY,
- INVALID_SUBSCRIPTION_ID);
-
private static VoidPropertyInvalidatedCache<Integer> sGetDefaultSubIdCache =
new VoidPropertyInvalidatedCache<>(ISub::getDefaultSubId,
CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
INVALID_SUBSCRIPTION_ID);
- private static VoidPropertyInvalidatedCache<Integer> sDefaultDataSubIdCache =
- new VoidPropertyInvalidatedCache<>(ISub::getDefaultDataSubId,
- CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY,
- INVALID_SUBSCRIPTION_ID);
-
private static VoidPropertyInvalidatedCache<Integer> sGetDefaultDataSubIdCache =
new VoidPropertyInvalidatedCache<>(ISub::getDefaultDataSubId,
CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
INVALID_SUBSCRIPTION_ID);
- private static VoidPropertyInvalidatedCache<Integer> sDefaultSmsSubIdCache =
- new VoidPropertyInvalidatedCache<>(ISub::getDefaultSmsSubId,
- CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY,
- INVALID_SUBSCRIPTION_ID);
-
private static VoidPropertyInvalidatedCache<Integer> sGetDefaultSmsSubIdCache =
new VoidPropertyInvalidatedCache<>(ISub::getDefaultSmsSubId,
CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
INVALID_SUBSCRIPTION_ID);
- private static VoidPropertyInvalidatedCache<Integer> sActiveDataSubIdCache =
- new VoidPropertyInvalidatedCache<>(ISub::getActiveDataSubscriptionId,
- CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY,
- INVALID_SUBSCRIPTION_ID);
-
private static VoidPropertyInvalidatedCache<Integer> sGetActiveDataSubscriptionIdCache =
new VoidPropertyInvalidatedCache<>(ISub::getActiveDataSubscriptionId,
CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
INVALID_SUBSCRIPTION_ID);
- private static IntegerPropertyInvalidatedCache<Integer> sSlotIndexCache =
- new IntegerPropertyInvalidatedCache<>(ISub::getSlotIndex,
- CACHE_KEY_SLOT_INDEX_PROPERTY,
- INVALID_SIM_SLOT_INDEX);
-
private static IntegerPropertyInvalidatedCache<Integer> sGetSlotIndexCache =
new IntegerPropertyInvalidatedCache<>(ISub::getSlotIndex,
CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
INVALID_SIM_SLOT_INDEX);
- private static IntegerPropertyInvalidatedCache<Integer> sSubIdCache =
- new IntegerPropertyInvalidatedCache<>(ISub::getSubId,
- CACHE_KEY_SLOT_INDEX_PROPERTY,
- INVALID_SUBSCRIPTION_ID);
-
private static IntegerPropertyInvalidatedCache<Integer> sGetSubIdCache =
new IntegerPropertyInvalidatedCache<>(ISub::getSubId,
CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
INVALID_SUBSCRIPTION_ID);
- /** Cache depends on getDefaultSubId, so we use the defaultSubId cache key */
- private static IntegerPropertyInvalidatedCache<Integer> sPhoneIdCache =
- new IntegerPropertyInvalidatedCache<>(ISub::getPhoneId,
- CACHE_KEY_DEFAULT_SUB_ID_PROPERTY,
- INVALID_PHONE_INDEX);
-
private static IntegerPropertyInvalidatedCache<Integer> sGetPhoneIdCache =
new IntegerPropertyInvalidatedCache<>(ISub::getPhoneId,
CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
INVALID_PHONE_INDEX);
- //TODO: Removed before U AOSP public release.
- private static VoidPropertyInvalidatedCache<Boolean> sIsSubscriptionManagerServiceEnabled =
- new VoidPropertyInvalidatedCache<>(ISub::isSubscriptionManagerServiceEnabled,
- CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_ENABLED_PROPERTY,
- false);
-
/**
* Generates a content {@link Uri} used to receive updates on simInfo change
* on the given subscriptionId
@@ -1455,17 +1392,6 @@
mContext = context;
}
- /**
- * @return {@code true} if the new subscription manager service is used. This is temporary and
- * will be removed before Android 14 release.
- *
- * @hide
- */
- //TODO: Removed before U AOSP public release.
- public static boolean isSubscriptionManagerServiceEnabled() {
- return sIsSubscriptionManagerServiceEnabled.query(null);
- }
-
private NetworkPolicyManager getNetworkPolicyManager() {
return (NetworkPolicyManager) mContext
.getSystemService(Context.NETWORK_POLICY_SERVICE);
@@ -1520,7 +1446,7 @@
+ " listener=" + listener);
}
// We use the TelephonyRegistry as it runs in the system and thus is always
- // available. Where as SubscriptionController could crash and not be available
+ // available.
TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager)
mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
if (telephonyRegistryManager != null) {
@@ -1550,7 +1476,7 @@
+ " listener=" + listener);
}
// We use the TelephonyRegistry as it runs in the system and thus is always
- // available where as SubscriptionController could crash and not be available
+ // available.
TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager)
mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
if (telephonyRegistryManager != null) {
@@ -1608,7 +1534,7 @@
}
// We use the TelephonyRegistry as it runs in the system and thus is always
- // available where as SubscriptionController could crash and not be available
+ // available.
TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager)
mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
if (telephonyRegistryManager != null) {
@@ -2149,9 +2075,9 @@
Log.e(LOG_TAG, "[removeSubscriptionInfoRecord]- ISub service is null");
return;
}
- int result = iSub.removeSubInfo(uniqueId, subscriptionType);
- if (result < 0) {
- Log.e(LOG_TAG, "Removal of subscription didn't succeed: error = " + result);
+ boolean result = iSub.removeSubInfo(uniqueId, subscriptionType);
+ if (!result) {
+ Log.e(LOG_TAG, "Removal of subscription didn't succeed");
} else {
logd("successfully removed subscription");
}
@@ -2236,8 +2162,7 @@
* subscriptionId doesn't have an associated slot index.
*/
public static int getSlotIndex(int subscriptionId) {
- if (isSubscriptionManagerServiceEnabled()) return sGetSlotIndexCache.query(subscriptionId);
- return sSlotIndexCache.query(subscriptionId);
+ return sGetSlotIndexCache.query(subscriptionId);
}
/**
@@ -2294,15 +2219,13 @@
return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
}
- if (isSubscriptionManagerServiceEnabled()) return sGetSubIdCache.query(slotIndex);
- return sSubIdCache.query(slotIndex);
+ return sGetSubIdCache.query(slotIndex);
}
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static int getPhoneId(int subId) {
- if (isSubscriptionManagerServiceEnabled()) return sGetPhoneIdCache.query(subId);
- return sPhoneIdCache.query(subId);
+ return sGetPhoneIdCache.query(subId);
}
private static void logd(String msg) {
@@ -2323,8 +2246,7 @@
* @return the "system" default subscription id.
*/
public static int getDefaultSubscriptionId() {
- if (isSubscriptionManagerServiceEnabled()) return sGetDefaultSubIdCache.query(null);
- return sDefaultSubIdCache.query(null);
+ return sGetDefaultSubIdCache.query(null);
}
/**
@@ -2412,8 +2334,7 @@
* @return the default SMS subscription Id.
*/
public static int getDefaultSmsSubscriptionId() {
- if (isSubscriptionManagerServiceEnabled()) return sGetDefaultSmsSubIdCache.query(null);
- return sDefaultSmsSubIdCache.query(null);
+ return sGetDefaultSmsSubIdCache.query(null);
}
/**
@@ -2447,8 +2368,7 @@
* @return the default data subscription Id.
*/
public static int getDefaultDataSubscriptionId() {
- if (isSubscriptionManagerServiceEnabled()) return sGetDefaultDataSubIdCache.query(null);
- return sDefaultDataSubIdCache.query(null);
+ return sGetDefaultDataSubIdCache.query(null);
}
/**
@@ -3912,10 +3832,7 @@
* @see TelephonyCallback.ActiveDataSubscriptionIdListener
*/
public static int getActiveDataSubscriptionId() {
- if (isSubscriptionManagerServiceEnabled()) {
- return sGetActiveDataSubscriptionIdCache.query(null);
- }
- return sActiveDataSubIdCache.query(null);
+ return sGetActiveDataSubscriptionIdCache.query(null);
}
/**
@@ -3934,61 +3851,16 @@
}
/** @hide */
- public static void invalidateDefaultSubIdCaches() {
- PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DEFAULT_SUB_ID_PROPERTY);
- }
-
- /** @hide */
- public static void invalidateDefaultDataSubIdCaches() {
- PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY);
- }
-
- /** @hide */
- public static void invalidateDefaultSmsSubIdCaches() {
- PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY);
- }
-
- /** @hide */
- public static void invalidateActiveDataSubIdCaches() {
- if (isSubscriptionManagerServiceEnabled()) {
- PropertyInvalidatedCache.invalidateCache(
- CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY);
- } else {
- PropertyInvalidatedCache.invalidateCache(CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY);
- }
- }
-
- /** @hide */
- public static void invalidateSlotIndexCaches() {
- PropertyInvalidatedCache.invalidateCache(CACHE_KEY_SLOT_INDEX_PROPERTY);
- }
-
- /** @hide */
public static void invalidateSubscriptionManagerServiceCaches() {
PropertyInvalidatedCache.invalidateCache(CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY);
}
- /** @hide */
- //TODO: Removed before U AOSP public release.
- public static void invalidateSubscriptionManagerServiceEnabledCaches() {
- PropertyInvalidatedCache.invalidateCache(
- CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_ENABLED_PROPERTY);
- }
-
/**
* Allows a test process to disable client-side caching operations.
*
* @hide
*/
public static void disableCaching() {
- sDefaultSubIdCache.disableLocal();
- sDefaultDataSubIdCache.disableLocal();
- sActiveDataSubIdCache.disableLocal();
- sDefaultSmsSubIdCache.disableLocal();
- sSlotIndexCache.disableLocal();
- sSubIdCache.disableLocal();
- sPhoneIdCache.disableLocal();
-
sGetDefaultSubIdCache.disableLocal();
sGetDefaultDataSubIdCache.disableLocal();
sGetActiveDataSubscriptionIdCache.disableLocal();
@@ -3996,8 +3868,6 @@
sGetSlotIndexCache.disableLocal();
sGetSubIdCache.disableLocal();
sGetPhoneIdCache.disableLocal();
-
- sIsSubscriptionManagerServiceEnabled.disableLocal();
}
/**
@@ -4005,14 +3875,6 @@
*
* @hide */
public static void clearCaches() {
- sDefaultSubIdCache.clear();
- sDefaultDataSubIdCache.clear();
- sActiveDataSubIdCache.clear();
- sDefaultSmsSubIdCache.clear();
- sSlotIndexCache.clear();
- sSubIdCache.clear();
- sPhoneIdCache.clear();
-
sGetDefaultSubIdCache.clear();
sGetDefaultDataSubIdCache.clear();
sGetActiveDataSubscriptionIdCache.clear();
@@ -4020,8 +3882,6 @@
sGetSlotIndexCache.clear();
sGetSubIdCache.clear();
sGetPhoneIdCache.clear();
-
- sIsSubscriptionManagerServiceEnabled.clear();
}
/**
diff --git a/telephony/java/android/telephony/satellite/stub/ISatelliteGateway.aidl b/telephony/java/android/telephony/satellite/stub/ISatelliteGateway.aidl
new file mode 100644
index 0000000..4f1a136
--- /dev/null
+++ b/telephony/java/android/telephony/satellite/stub/ISatelliteGateway.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 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.telephony.satellite.stub;
+
+/**
+ * {@hide}
+ */
+oneway interface ISatelliteGateway {
+ // An empty service because Telephony does not need to use any APIs from this service.
+ // Once satellite modem is enabled, Telephony will bind to the ISatelliteGateway service; and
+ // when satellite modem is disabled, Telephony will unbind to the service.
+}
diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteGatewayService.java b/telephony/java/android/telephony/satellite/stub/SatelliteGatewayService.java
new file mode 100644
index 0000000..f4514a6
--- /dev/null
+++ b/telephony/java/android/telephony/satellite/stub/SatelliteGatewayService.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 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.telephony.satellite.stub;
+
+import android.annotation.SdkConstant;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+import com.android.telephony.Rlog;
+
+/**
+ * Main SatelliteGatewayService implementation, which binds via the Telephony SatelliteController.
+ * Services that extend SatelliteGatewayService must register the service in their AndroidManifest
+ * to be detected by the framework. The application must declare that they require the
+ * "android.permission.BIND_SATELLITE_GATEWAY_SERVICE" permission to ensure that nothing else can
+ * bind to their service except the Telephony framework. The SatelliteGatewayService definition in
+ * the manifest must follow the following format:
+ *
+ * ...
+ * <service android:name=".EgSatelliteGatewayService"
+ * android:permission="android.permission.BIND_SATELLITE_GATEWAY_SERVICE" >
+ * ...
+ * <intent-filter>
+ * <action android:name="android.telephony.satellite.SatelliteGatewayService" />
+ * </intent-filter>
+ * </service>
+ * ...
+ *
+ * The telephony framework will then bind to the SatelliteGatewayService defined in the manifest if
+ * it is the default SatelliteGatewayService defined in the device overlay
+ * "config_satellite_gateway_service_package".
+ * @hide
+ */
+public abstract class SatelliteGatewayService extends Service {
+ private static final String TAG = "SatelliteGatewayService";
+
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE =
+ "android.telephony.satellite.SatelliteGatewayService";
+
+ private final IBinder mBinder = new ISatelliteGateway.Stub() {};
+
+ /**
+ * @hide
+ */
+ @Override
+ public final IBinder onBind(Intent intent) {
+ if (SERVICE_INTERFACE.equals(intent.getAction())) {
+ Rlog.d(TAG, "SatelliteGatewayService bound");
+ return mBinder;
+ }
+ return null;
+ }
+
+ /**
+ * @return The binder for the ISatelliteGateway.
+ * @hide
+ */
+ public final IBinder getBinder() {
+ return mBinder;
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 6a5380d..21a6b44 100644
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -129,9 +129,9 @@
* @param uniqueId This is the unique identifier for the subscription within the specific
* subscription type.
* @param subscriptionType the type of subscription to be removed
- * @return 0 if success, < 0 on error.
+ * @return true if success, false on error.
*/
- int removeSubInfo(String uniqueId, int subscriptionType);
+ boolean removeSubInfo(String uniqueId, int subscriptionType);
/**
* Set SIM icon tint color by simInfo index
@@ -260,7 +260,7 @@
int[] getActiveSubIdList(boolean visibleOnly);
- int setSubscriptionProperty(int subId, String propKey, String propValue);
+ void setSubscriptionProperty(int subId, String propKey, String propValue);
String getSubscriptionProperty(int subId, String propKey, String callingPackage,
String callingFeatureId);
@@ -353,13 +353,6 @@
*/
List<SubscriptionInfo> getSubscriptionInfoListAssociatedWithUser(in UserHandle userHandle);
- /**
- * @return {@code true} if using SubscriptionManagerService instead of
- * SubscriptionController.
- */
- //TODO: Removed before U AOSP public release.
- boolean isSubscriptionManagerServiceEnabled();
-
/**
* Called during setup wizard restore flow to attempt to restore the backed up sim-specific
* configs to device for all existing SIMs in the subscription database
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index ee9d6c1..282b64d 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2991,6 +2991,15 @@
boolean setSatelliteServicePackageName(in String servicePackageName);
/**
+ * This API can be used by only CTS to update satellite gateway service package name.
+ *
+ * @param servicePackageName The package name of the satellite gateway service.
+ * @return {@code true} if the satellite gateway service is set successfully,
+ * {@code false} otherwise.
+ */
+ boolean setSatelliteGatewayServicePackageName(in String servicePackageName);
+
+ /**
* This API can be used by only CTS to update the timeout duration in milliseconds that
* satellite should stay at listening mode to wait for the next incoming page before disabling
* listening mode.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt
index 18e49fe..ae9ca80 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt
@@ -102,7 +102,7 @@
@Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
- @Postsubmit
+ @Ignore("Not applicable to this CUJ. App is full screen at the end")
@Test
override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
@@ -127,11 +127,11 @@
@Test
override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
- @Postsubmit
+ @Ignore("Not applicable to this CUJ. App is full screen at the end")
@Test
override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
- @Postsubmit
+ @Ignore("Not applicable to this CUJ. App is full screen at the end")
@Test
override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
@@ -145,7 +145,7 @@
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
- @Postsubmit
+ @Ignore("Not applicable to this CUJ. App is full screen at the end")
@Test
override fun navBarWindowIsVisibleAtStartAndEnd() {
super.navBarWindowIsVisibleAtStartAndEnd()
diff --git a/tests/SharedLibraryLoadingTest/AndroidTest.xml b/tests/SharedLibraryLoadingTest/AndroidTest.xml
index 947453d..ad05847 100644
--- a/tests/SharedLibraryLoadingTest/AndroidTest.xml
+++ b/tests/SharedLibraryLoadingTest/AndroidTest.xml
@@ -22,7 +22,6 @@
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="cleanup" value="false" />
<option name="remount-system" value="true" />
<option name="push"
value="SharedLibraryLoadingTests_StandardSharedLibrary.apk->/product/app/SharedLibraryLoadingTests_StandardSharedLibrary.apk" />
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java
index 166fbdd..c6e675a 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/NetworkProviderInfo.java
@@ -84,6 +84,12 @@
public @interface DeviceType {
}
+ /**
+ * Key in extras bundle indicating that the device battery is charging.
+ * @hide
+ */
+ public static final String EXTRA_KEY_IS_BATTERY_CHARGING = "is_battery_charging";
+
@DeviceType
private final int mDeviceType;
private final String mDeviceName;