Merge "Add merged local insets to proto" 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/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index c707069..2550a27 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -1351,6 +1351,7 @@
}
@Override
+ @EconomyManager.EnabledMode
public int getEnabledMode() {
return InternalResourceService.this.getEnabledMode();
}
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/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index ebd525e..6592019 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -303,7 +303,7 @@
private final Context mContext;
private final boolean mWcgEnabled;
private final ColorManagementProxy mCmProxy;
- private Boolean mIsLockscreenLiveWallpaperEnabled = null;
+ private static Boolean sIsLockscreenLiveWallpaperEnabled = null;
/**
* Special drawable that draws a wallpaper as fast as possible. Assumes
@@ -823,18 +823,18 @@
@TestApi
public boolean isLockscreenLiveWallpaperEnabled() {
if (sGlobals == null) {
- mIsLockscreenLiveWallpaperEnabled = SystemProperties.getBoolean(
+ sIsLockscreenLiveWallpaperEnabled = SystemProperties.getBoolean(
"persist.wm.debug.lockscreen_live_wallpaper", false);
}
- if (mIsLockscreenLiveWallpaperEnabled == null) {
+ if (sIsLockscreenLiveWallpaperEnabled == null) {
try {
- mIsLockscreenLiveWallpaperEnabled =
+ sIsLockscreenLiveWallpaperEnabled =
sGlobals.mService.isLockscreenLiveWallpaperEnabled();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- return mIsLockscreenLiveWallpaperEnabled;
+ return sIsLockscreenLiveWallpaperEnabled;
}
/**
@@ -2757,7 +2757,7 @@
public static InputStream openDefaultWallpaper(Context context, @SetWallpaperFlags int which) {
final String whichProp;
final int defaultResId;
- if (which == FLAG_LOCK) {
+ if (which == FLAG_LOCK && !sIsLockscreenLiveWallpaperEnabled) {
/* Factory-default lock wallpapers are not yet supported
whichProp = PROP_LOCK_WALLPAPER;
defaultResId = com.android.internal.R.drawable.default_lock_wallpaper;
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 154068e..74a69a6 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -16,6 +16,7 @@
package android.content;
+import static android.app.sdksandbox.SdkSandboxManager.ACTION_START_SANDBOXED_ACTIVITY;
import static android.content.ContentProvider.maybeAddUserId;
import android.Manifest;
@@ -12463,4 +12464,19 @@
public boolean isDocument() {
return (mFlags & FLAG_ACTIVITY_NEW_DOCUMENT) == FLAG_ACTIVITY_NEW_DOCUMENT;
}
+
+ /** @hide */
+ public boolean isSandboxActivity(@NonNull Context context) {
+ if (mAction != null && mAction.equals(ACTION_START_SANDBOXED_ACTIVITY)) {
+ return true;
+ }
+ final String sandboxPackageName = context.getPackageManager().getSdkSandboxPackageName();
+ if (mPackage != null && mPackage.equals(sandboxPackageName)) {
+ return true;
+ }
+ if (mComponent != null && mComponent.getPackageName().equals(sandboxPackageName)) {
+ return true;
+ }
+ return false;
+ }
}
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/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 55b20e1..e0af913 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -342,6 +342,14 @@
return;
}
+ if (getEnrolledFaces(userId).size()
+ >= mContext.getResources().getInteger(R.integer.config_faceMaxTemplatesPerUser)) {
+ callback.onEnrollmentError(FACE_ERROR_HW_UNAVAILABLE,
+ getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */));
+ return;
+ }
+
if (mService != null) {
try {
mEnrollmentCallback = callback;
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/provider/Settings.java b/core/java/android/provider/Settings.java
index d75d186..561f798 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14906,6 +14906,14 @@
public static final String ENABLE_TARE = "enable_tare";
/**
+ * Whether to show the TARE page in Developer Options or not.
+ * 1 = true, everything else = false
+ *
+ * @hide
+ */
+ public static final String SHOW_TARE_DEVELOPER_OPTIONS = "show_tare_developer_options";
+
+ /**
* Settings for AlarmManager's TARE EconomicPolicy (list of its economic factors).
*
* Keys are listed in {@link android.app.tare.EconomyManager}.
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 77bbeb5..9d3d70d 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -112,6 +112,7 @@
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
/**
@@ -431,6 +432,7 @@
Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0,
mergedConfiguration);
+ mIWallpaperEngine.mPendingResizeCount.incrementAndGet();
mCaller.sendMessage(msg);
}
@@ -1051,6 +1053,10 @@
out.print(prefix); out.print("mZoom="); out.println(mZoom);
out.print(prefix); out.print("mPreviewSurfacePosition=");
out.println(mPreviewSurfacePosition);
+ final int pendingCount = mIWallpaperEngine.mPendingResizeCount.get();
+ if (pendingCount != 0) {
+ out.print(prefix); out.print("mPendingResizeCount="); out.println(pendingCount);
+ }
synchronized (mLock) {
out.print(prefix); out.print("mPendingXOffset="); out.print(mPendingXOffset);
out.print(" mPendingXOffset="); out.println(mPendingXOffset);
@@ -1113,10 +1119,6 @@
}
}
- private void updateConfiguration(MergedConfiguration mergedConfiguration) {
- mMergedConfiguration.setTo(mergedConfiguration);
- }
-
void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
if (mDestroyed) {
Log.w(TAG, "Ignoring updateSurface due to destroyed");
@@ -1165,7 +1167,7 @@
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
final Configuration config = mMergedConfiguration.getMergedConfiguration();
- final Rect maxBounds = config.windowConfiguration.getMaxBounds();
+ final Rect maxBounds = new Rect(config.windowConfiguration.getMaxBounds());
if (myWidth == ViewGroup.LayoutParams.MATCH_PARENT
&& myHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
mLayout.width = myWidth;
@@ -1221,6 +1223,17 @@
final int relayoutResult = mSession.relayout(mWindow, mLayout, mWidth, mHeight,
View.VISIBLE, 0, 0, 0, mWinFrames, mMergedConfiguration,
mSurfaceControl, mInsetsState, mTempControls, mSyncSeqIdBundle);
+ final Rect outMaxBounds = mMergedConfiguration.getMergedConfiguration()
+ .windowConfiguration.getMaxBounds();
+ if (!outMaxBounds.equals(maxBounds)) {
+ Log.i(TAG, "Retry updateSurface because bounds changed from relayout: "
+ + maxBounds + " -> " + outMaxBounds);
+ mSurfaceHolder.mSurfaceLock.unlock();
+ mDrawingAllowed = false;
+ mCaller.sendMessage(mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
+ redrawNeeded ? 1 : 0));
+ return;
+ }
final int transformHint = SurfaceControl.rotationToBufferTransform(
(mDisplay.getInstallOrientation() + mDisplay.getRotation()) % 4);
@@ -1488,6 +1501,8 @@
mWallpaperDimAmount = mDefaultDimAmount;
mPreviousWallpaperDimAmount = mWallpaperDimAmount;
mDisplayState = mDisplay.getCommittedState();
+ mMergedConfiguration.setOverrideConfiguration(
+ mDisplayContext.getResources().getConfiguration());
if (DEBUG) Log.v(TAG, "onCreate(): " + this);
Trace.beginSection("WPMS.Engine.onCreate");
@@ -2324,6 +2339,8 @@
final IBinder mWindowToken;
final int mWindowType;
final boolean mIsPreview;
+ final AtomicInteger mPendingResizeCount = new AtomicInteger();
+ boolean mReportDraw;
boolean mShownReported;
int mReqWidth;
int mReqHeight;
@@ -2579,11 +2596,7 @@
mEngine.doCommand(cmd);
} break;
case MSG_WINDOW_RESIZED: {
- final boolean reportDraw = message.arg1 != 0;
- mEngine.updateConfiguration(((MergedConfiguration) message.obj));
- mEngine.updateSurface(true, false, reportDraw);
- mEngine.doOffsetsChanged(true);
- mEngine.scaleAndCropScreenshot();
+ handleResized((MergedConfiguration) message.obj, message.arg1 != 0);
} break;
case MSG_WINDOW_MOVED: {
// Do nothing. What does it mean for a Wallpaper to move?
@@ -2631,6 +2644,40 @@
Log.w(TAG, "Unknown message type " + message.what);
}
}
+
+ /**
+ * In general this performs relayout for IWindow#resized. If there are several pending
+ * (in the message queue) MSG_WINDOW_RESIZED from server side, only the last one will be
+ * handled (ignore intermediate states). Note that this procedure cannot be skipped if the
+ * configuration is not changed because this is also used to dispatch insets changes.
+ */
+ private void handleResized(MergedConfiguration config, boolean reportDraw) {
+ // The config can be null when retrying for a changed config from relayout, otherwise
+ // it is from IWindow#resized which always sends non-null config.
+ final int pendingCount = config != null ? mPendingResizeCount.decrementAndGet() : -1;
+ if (reportDraw) {
+ mReportDraw = true;
+ }
+ if (pendingCount > 0) {
+ if (DEBUG) {
+ Log.d(TAG, "Skip outdated resize, bounds="
+ + config.getMergedConfiguration().windowConfiguration.getMaxBounds()
+ + " pendingCount=" + pendingCount);
+ }
+ return;
+ }
+ if (config != null) {
+ if (DEBUG) {
+ Log.d(TAG, "Update config from resized, bounds="
+ + config.getMergedConfiguration().windowConfiguration.getMaxBounds());
+ }
+ mEngine.mMergedConfiguration.setTo(config);
+ }
+ mEngine.updateSurface(true /* forceRelayout */, false /* forceReport */, mReportDraw);
+ mReportDraw = false;
+ mEngine.doOffsetsChanged(true);
+ mEngine.scaleAndCropScreenshot();
+ }
}
/**
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]\n@com.android.internal.util.DataClass(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]\n@com.android.internal.util.DataClass(genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 75f1666..6c5f195 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -480,9 +480,9 @@
: inset != 0;
if (outState != null && source != null) {
- outState.getOrCreateSource(source.getId(), source.getType())
+ outState.addSource(new InsetsSource(source)
.setVisible(visible)
- .setFrame(mTmpFrame);
+ .setFrame(mTmpFrame));
}
// If the system is controlling the insets source, the leash can be null.
diff --git a/core/java/android/view/InsetsFrameProvider.java b/core/java/android/view/InsetsFrameProvider.java
index 2d7dc31..a69af24 100644
--- a/core/java/android/view/InsetsFrameProvider.java
+++ b/core/java/android/view/InsetsFrameProvider.java
@@ -23,6 +23,7 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.view.InsetsSource.Flags;
import android.view.WindowInsets.Type.InsetsType;
import java.util.Arrays;
@@ -86,6 +87,13 @@
private Insets mInsetsSize = null;
/**
+ * Various behavioral options/flags. Default is none.
+ *
+ * @see Flags
+ */
+ private @Flags int mFlags;
+
+ /**
* If null, the size set in insetsSize will be applied to all window types. If it contains
* element of some types, the insets reported to the window with that types will be overridden.
*/
@@ -149,6 +157,15 @@
return mSource;
}
+ public InsetsFrameProvider setFlags(@Flags int flags, @Flags int mask) {
+ mFlags = (mFlags & ~mask) | (flags & mask);
+ return this;
+ }
+
+ public @Flags int getFlags() {
+ return mFlags;
+ }
+
public InsetsFrameProvider setInsetsSize(Insets insetsSize) {
mInsetsSize = insetsSize;
return this;
@@ -198,6 +215,7 @@
sb.append(", index=").append(mIndex);
sb.append(", type=").append(WindowInsets.Type.toString(mType));
sb.append(", source=").append(sourceToString(mSource));
+ sb.append(", flags=[").append(InsetsSource.flagsToString(mFlags)).append("]");
if (mInsetsSize != null) {
sb.append(", insetsSize=").append(mInsetsSize);
}
@@ -230,6 +248,7 @@
mIndex = in.readInt();
mType = in.readInt();
mSource = in.readInt();
+ mFlags = in.readInt();
mInsetsSize = in.readTypedObject(Insets.CREATOR);
mInsetsSizeOverrides = in.createTypedArray(InsetsSizeOverride.CREATOR);
mArbitraryRectangle = in.readTypedObject(Rect.CREATOR);
@@ -241,6 +260,7 @@
out.writeInt(mIndex);
out.writeInt(mType);
out.writeInt(mSource);
+ out.writeInt(mFlags);
out.writeTypedObject(mInsetsSize, flags);
out.writeTypedArray(mInsetsSizeOverrides, flags);
out.writeTypedObject(mArbitraryRectangle, flags);
@@ -260,7 +280,7 @@
}
final InsetsFrameProvider other = (InsetsFrameProvider) o;
return Objects.equals(mOwner, other.mOwner) && mIndex == other.mIndex
- && mType == other.mType && mSource == other.mSource
+ && mType == other.mType && mSource == other.mSource && mFlags == other.mFlags
&& Objects.equals(mInsetsSize, other.mInsetsSize)
&& Arrays.equals(mInsetsSizeOverrides, other.mInsetsSizeOverrides)
&& Objects.equals(mArbitraryRectangle, other.mArbitraryRectangle);
@@ -268,7 +288,7 @@
@Override
public int hashCode() {
- return Objects.hash(mOwner, mIndex, mType, mSource, mInsetsSize,
+ return Objects.hash(mOwner, mIndex, mType, mSource, mFlags, mInsetsSize,
Arrays.hashCode(mInsetsSizeOverrides), mArbitraryRectangle);
}
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 3947738..bd48771 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -22,6 +22,7 @@
import static android.view.InsetsSourceProto.VISIBLE_FRAME;
import static android.view.WindowInsets.Type.ime;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -33,7 +34,10 @@
import android.view.WindowInsets.Type.InsetsType;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
+import java.util.StringJoiner;
/**
* Represents the state of a single entity generating insets for clients.
@@ -45,6 +49,24 @@
public static final int ID_IME = createId(null, 0, ime());
/**
+ * Controls whether this source suppresses the scrim. If the scrim is ignored, the system won't
+ * draw a semi-transparent scrim behind the system bar area even when the bar contrast is
+ * enforced.
+ *
+ * @see android.R.styleable#Window_enforceStatusBarContrast
+ * @see android.R.styleable#Window_enforceNavigationBarContrast
+ */
+ public static final int FLAG_SUPPRESS_SCRIM = 1;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = "FLAG_", value = {
+ FLAG_SUPPRESS_SCRIM,
+ })
+ public @interface Flags {}
+
+ private @Flags int mFlags;
+
+ /**
* An unique integer to identify this source across processes.
*/
private final int mId;
@@ -75,6 +97,7 @@
mVisibleFrame = other.mVisibleFrame != null
? new Rect(other.mVisibleFrame)
: null;
+ mFlags = other.mFlags;
mInsetsRoundedCornerFrame = other.mInsetsRoundedCornerFrame;
}
@@ -84,6 +107,7 @@
mVisibleFrame = other.mVisibleFrame != null
? new Rect(other.mVisibleFrame)
: null;
+ mFlags = other.mFlags;
mInsetsRoundedCornerFrame = other.mInsetsRoundedCornerFrame;
}
@@ -107,6 +131,11 @@
return this;
}
+ public InsetsSource setFlags(@Flags int flags) {
+ mFlags = flags;
+ return this;
+ }
+
public int getId() {
return mId;
}
@@ -127,6 +156,10 @@
return mVisible;
}
+ public @Flags int getFlags() {
+ return mFlags;
+ }
+
boolean isUserControllable() {
// If mVisibleFrame is null, it will be the same area as mFrame.
return mVisibleFrame == null || !mVisibleFrame.isEmpty();
@@ -254,6 +287,14 @@
+ WindowInsets.Type.indexOf(type);
}
+ public static String flagsToString(@Flags int flags) {
+ final StringJoiner joiner = new StringJoiner(" ");
+ if ((flags & FLAG_SUPPRESS_SCRIM) != 0) {
+ joiner.add("SUPPRESS_SCRIM");
+ }
+ return joiner.toString();
+ }
+
/**
* Export the state of {@link InsetsSource} into a protocol buffer output stream.
*
@@ -280,6 +321,7 @@
pw.print(" visibleFrame="); pw.print(mVisibleFrame.toShortString());
}
pw.print(" visible="); pw.print(mVisible);
+ pw.print(" flags="); pw.print(flagsToString(mFlags));
pw.print(" insetsRoundedCornerFrame="); pw.print(mInsetsRoundedCornerFrame);
pw.println();
}
@@ -302,6 +344,7 @@
if (mId != that.mId) return false;
if (mType != that.mType) return false;
if (mVisible != that.mVisible) return false;
+ if (mFlags != that.mFlags) return false;
if (excludeInvisibleImeFrames && !mVisible && mType == WindowInsets.Type.ime()) return true;
if (!Objects.equals(mVisibleFrame, that.mVisibleFrame)) return false;
if (mInsetsRoundedCornerFrame != that.mInsetsRoundedCornerFrame) return false;
@@ -310,7 +353,8 @@
@Override
public int hashCode() {
- return Objects.hash(mId, mType, mFrame, mVisibleFrame, mVisible, mInsetsRoundedCornerFrame);
+ return Objects.hash(mId, mType, mFrame, mVisibleFrame, mVisible, mFlags,
+ mInsetsRoundedCornerFrame);
}
public InsetsSource(Parcel in) {
@@ -323,6 +367,7 @@
mVisibleFrame = null;
}
mVisible = in.readBoolean();
+ mFlags = in.readInt();
mInsetsRoundedCornerFrame = in.readBoolean();
}
@@ -343,6 +388,7 @@
dest.writeInt(0);
}
dest.writeBoolean(mVisible);
+ dest.writeInt(mFlags);
dest.writeBoolean(mInsetsRoundedCornerFrame);
}
@@ -352,6 +398,7 @@
+ " mType=" + WindowInsets.Type.toString(mType)
+ " mFrame=" + mFrame.toShortString()
+ " mVisible=" + mVisible
+ + " mFlags=[" + flagsToString(mFlags) + "]"
+ (mInsetsRoundedCornerFrame ? " insetsRoundedCornerFrame" : "")
+ "}";
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index bd249c4..5b974cd 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -143,9 +143,14 @@
boolean[] typeVisibilityMap = new boolean[Type.SIZE];
final Rect relativeFrame = new Rect(frame);
final Rect relativeFrameMax = new Rect(frame);
+ @InsetsType int suppressScrimTypes = 0;
for (int i = mSources.size() - 1; i >= 0; i--) {
final InsetsSource source = mSources.valueAt(i);
+ if ((source.getFlags() & InsetsSource.FLAG_SUPPRESS_SCRIM) != 0) {
+ suppressScrimTypes |= source.getType();
+ }
+
processSource(source, relativeFrame, false /* ignoreVisibility */, typeInsetsMap,
idSideMap, typeVisibilityMap);
@@ -177,7 +182,7 @@
}
return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
- alwaysConsumeSystemBars, calculateRelativeCutout(frame),
+ alwaysConsumeSystemBars, suppressScrimTypes, calculateRelativeCutout(frame),
calculateRelativeRoundedCorners(frame),
calculateRelativePrivacyIndicatorBounds(frame),
calculateRelativeDisplayShape(frame),
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/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index fd55d8d..4acaea8 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -91,6 +91,7 @@
*/
private final boolean mAlwaysConsumeSystemBars;
+ private final @InsetsType int mSuppressScrimTypes;
private final boolean mSystemWindowInsetsConsumed;
private final boolean mStableInsetsConsumed;
private final boolean mDisplayCutoutConsumed;
@@ -116,8 +117,8 @@
static {
CONSUMED = new WindowInsets(createCompatTypeMap(null), createCompatTypeMap(null),
- createCompatVisibilityMap(createCompatTypeMap(null)), false, false, null, null,
- null, null, systemBars(), false);
+ createCompatVisibilityMap(createCompatTypeMap(null)), false, false, 0, null,
+ null, null, null, systemBars(), false);
}
/**
@@ -136,7 +137,8 @@
@Nullable Insets[] typeMaxInsetsMap,
boolean[] typeVisibilityMap,
boolean isRound,
- boolean alwaysConsumeSystemBars, DisplayCutout displayCutout,
+ boolean alwaysConsumeSystemBars, @InsetsType int suppressScrimTypes,
+ DisplayCutout displayCutout,
RoundedCorners roundedCorners,
PrivacyIndicatorBounds privacyIndicatorBounds,
DisplayShape displayShape,
@@ -154,6 +156,7 @@
mTypeVisibilityMap = typeVisibilityMap;
mIsRound = isRound;
mAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
+ mSuppressScrimTypes = suppressScrimTypes;
mCompatInsetsTypes = compatInsetsTypes;
mCompatIgnoreVisibility = compatIgnoreVisibility;
@@ -175,7 +178,8 @@
this(src.mSystemWindowInsetsConsumed ? null : src.mTypeInsetsMap,
src.mStableInsetsConsumed ? null : src.mTypeMaxInsetsMap,
src.mTypeVisibilityMap, src.mIsRound,
- src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src),
+ src.mAlwaysConsumeSystemBars, src.mSuppressScrimTypes,
+ displayCutoutCopyConstructorArgument(src),
src.mRoundedCorners,
src.mPrivacyIndicatorBounds,
src.mDisplayShape,
@@ -231,8 +235,8 @@
/** @hide */
@UnsupportedAppUsage
public WindowInsets(Rect systemWindowInsets) {
- this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null,
- null, null, null, systemBars(), false /* compatIgnoreVisibility */);
+ this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, 0,
+ null, null, null, null, systemBars(), false /* compatIgnoreVisibility */);
}
/**
@@ -552,7 +556,7 @@
return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap,
mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
mTypeVisibilityMap,
- mIsRound, mAlwaysConsumeSystemBars,
+ mIsRound, mAlwaysConsumeSystemBars, mSuppressScrimTypes,
null /* displayCutout */, mRoundedCorners, mPrivacyIndicatorBounds, mDisplayShape,
mCompatInsetsTypes, mCompatIgnoreVisibility);
}
@@ -603,7 +607,7 @@
public WindowInsets consumeSystemWindowInsets() {
return new WindowInsets(null, null,
mTypeVisibilityMap,
- mIsRound, mAlwaysConsumeSystemBars,
+ mIsRound, mAlwaysConsumeSystemBars, mSuppressScrimTypes,
// If the system window insets types contain displayCutout, we should also consume
// it.
(mCompatInsetsTypes & displayCutout()) != 0
@@ -895,6 +899,13 @@
return mAlwaysConsumeSystemBars;
}
+ /**
+ * @hide
+ */
+ public @InsetsType int getSuppressScrimTypes() {
+ return mSuppressScrimTypes;
+ }
+
@Override
public String toString() {
StringBuilder result = new StringBuilder("WindowInsets{\n ");
@@ -919,7 +930,9 @@
result.append("\n ");
result.append(mDisplayShape != null ? "displayShape=" + mDisplayShape : "");
result.append("\n ");
- result.append("compatInsetsTypes=" + mCompatInsetsTypes);
+ result.append("suppressScrimTypes=" + Type.toString(mSuppressScrimTypes));
+ result.append("\n ");
+ result.append("compatInsetsTypes=" + Type.toString(mCompatInsetsTypes));
result.append("\n ");
result.append("compatIgnoreVisibility=" + mCompatIgnoreVisibility);
result.append("\n ");
@@ -1014,7 +1027,7 @@
? null
: insetInsets(mTypeMaxInsetsMap, left, top, right, bottom),
mTypeVisibilityMap,
- mIsRound, mAlwaysConsumeSystemBars,
+ mIsRound, mAlwaysConsumeSystemBars, mSuppressScrimTypes,
mDisplayCutoutConsumed
? null
: mDisplayCutout == null
@@ -1038,6 +1051,7 @@
return mIsRound == that.mIsRound
&& mAlwaysConsumeSystemBars == that.mAlwaysConsumeSystemBars
+ && mSuppressScrimTypes == that.mSuppressScrimTypes
&& mSystemWindowInsetsConsumed == that.mSystemWindowInsetsConsumed
&& mStableInsetsConsumed == that.mStableInsetsConsumed
&& mDisplayCutoutConsumed == that.mDisplayCutoutConsumed
@@ -1054,8 +1068,9 @@
public int hashCode() {
return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout, mRoundedCorners,
- mAlwaysConsumeSystemBars, mSystemWindowInsetsConsumed, mStableInsetsConsumed,
- mDisplayCutoutConsumed, mPrivacyIndicatorBounds, mDisplayShape);
+ mAlwaysConsumeSystemBars, mSuppressScrimTypes, mSystemWindowInsetsConsumed,
+ mStableInsetsConsumed, mDisplayCutoutConsumed, mPrivacyIndicatorBounds,
+ mDisplayShape);
}
@@ -1120,6 +1135,7 @@
private boolean mIsRound;
private boolean mAlwaysConsumeSystemBars;
+ private @InsetsType int mSuppressScrimTypes;
private PrivacyIndicatorBounds mPrivacyIndicatorBounds = new PrivacyIndicatorBounds();
@@ -1147,6 +1163,7 @@
mRoundedCorners = insets.mRoundedCorners;
mIsRound = insets.mIsRound;
mAlwaysConsumeSystemBars = insets.mAlwaysConsumeSystemBars;
+ mSuppressScrimTypes = insets.mSuppressScrimTypes;
mPrivacyIndicatorBounds = insets.mPrivacyIndicatorBounds;
mDisplayShape = insets.mDisplayShape;
}
@@ -1420,6 +1437,13 @@
return this;
}
+ /** @hide */
+ @NonNull
+ public Builder setSuppressScrimTypes(@InsetsType int suppressScrimTypes) {
+ mSuppressScrimTypes = suppressScrimTypes;
+ return this;
+ }
+
/**
* Builds a {@link WindowInsets} instance.
*
@@ -1429,8 +1453,8 @@
public WindowInsets build() {
return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
- mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout, mRoundedCorners,
- mPrivacyIndicatorBounds, mDisplayShape, systemBars(),
+ mIsRound, mAlwaysConsumeSystemBars, mSuppressScrimTypes, mDisplayCutout,
+ mRoundedCorners, mPrivacyIndicatorBounds, mDisplayShape, systemBars(),
false /* compatIgnoreVisibility */);
}
}
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/os/anr/AnrLatencyTracker.java b/core/java/com/android/internal/os/anr/AnrLatencyTracker.java
index 096d1cd..6fa6fa5 100644
--- a/core/java/com/android/internal/os/anr/AnrLatencyTracker.java
+++ b/core/java/com/android/internal/os/anr/AnrLatencyTracker.java
@@ -28,12 +28,15 @@
import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__START_FOREGROUND_SERVICE;
import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__UNKNOWN_ANR_TYPE;
+import android.annotation.IntDef;
import android.os.SystemClock;
import android.os.Trace;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -44,6 +47,22 @@
*/
public class AnrLatencyTracker implements AutoCloseable {
+ /** Status of the early dumped pid. */
+ @IntDef(value = {
+ EarlyDumpStatus.UNKNOWN,
+ EarlyDumpStatus.SUCCEEDED,
+ EarlyDumpStatus.FAILED_TO_CREATE_FILE,
+ EarlyDumpStatus.TIMED_OUT
+ })
+
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface EarlyDumpStatus {
+ int UNKNOWN = 1;
+ int SUCCEEDED = 2;
+ int FAILED_TO_CREATE_FILE = 3;
+ int TIMED_OUT = 4;
+ }
+
private static final AtomicInteger sNextAnrRecordPlacedOnQueueCookieGenerator =
new AtomicInteger();
@@ -77,7 +96,16 @@
private int mAnrQueueSize;
private int mAnrType;
- private int mDumpedProcessesCount = 0;
+ private final AtomicInteger mDumpedProcessesCount = new AtomicInteger(0);
+
+ private volatile @EarlyDumpStatus int mEarlyDumpStatus =
+ EarlyDumpStatus.UNKNOWN;
+ private volatile long mTempFileDumpingStartUptime;
+ private volatile long mTempFileDumpingDuration = 0;
+ private long mCopyingFirstPidStartUptime;
+ private long mCopyingFirstPidDuration = 0;
+ private long mEarlyDumpRequestSubmissionUptime = 0;
+ private long mEarlyDumpExecutorPidCount = 0;
private long mFirstPidsDumpingStartUptime;
private long mFirstPidsDumpingDuration = 0;
@@ -88,7 +116,7 @@
private boolean mIsPushed = false;
private boolean mIsSkipped = false;
-
+ private boolean mCopyingFirstPidSucceeded = false;
private final int mAnrRecordPlacedOnQueueCookie =
sNextAnrRecordPlacedOnQueueCookieGenerator.incrementAndGet();
@@ -111,6 +139,15 @@
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
+ /**
+ * Records the number of processes we are currently early-dumping, this number includes the
+ * current ANR's main process.
+ */
+ public void earlyDumpRequestSubmittedWithSize(int currentProcessedPidCount) {
+ mEarlyDumpRequestSubmissionUptime = getUptimeMillis();
+ mEarlyDumpExecutorPidCount = currentProcessedPidCount;
+ }
+
/** Records the placing of the AnrHelper.AnrRecord instance on the processing queue. */
public void anrRecordPlacingOnQueueWithSize(int queueSize) {
mAnrRecordPlacedOnQueueUptime = getUptimeMillis();
@@ -210,48 +247,89 @@
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
- /** Records the start of pid dumping to file (subject and criticalEventSection). */
+ /** Records the start of pid dumping to file. */
public void dumpingPidStarted(int pid) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dumpingPid#" + pid);
}
- /** Records the end of pid dumping to file (subject and criticalEventSection). */
+ /** Records the end of pid dumping to file. */
public void dumpingPidEnded() {
- mDumpedProcessesCount++;
+ mDumpedProcessesCount.incrementAndGet();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
- /** Records the start of pid dumping to file (subject and criticalEventSection). */
+ /** Records the start of first pids dumping to file. */
public void dumpingFirstPidsStarted() {
mFirstPidsDumpingStartUptime = getUptimeMillis();
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dumpingFirstPids");
}
- /** Records the end of pid dumping to file (subject and criticalEventSection). */
+ /** Records the end of first pids dumping to file. */
public void dumpingFirstPidsEnded() {
mFirstPidsDumpingDuration = getUptimeMillis() - mFirstPidsDumpingStartUptime;
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
- /** Records the start of pid dumping to file (subject and criticalEventSection). */
+
+ /** Records the start of the copying of the pre-dumped first pid. */
+ public void copyingFirstPidStarted() {
+ mCopyingFirstPidStartUptime = getUptimeMillis();
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "copyingFirstPid");
+ }
+
+ /** Records the end of the copying of the pre-dumped first pid. */
+ public void copyingFirstPidEnded(boolean copySucceeded) {
+ mCopyingFirstPidDuration = getUptimeMillis() - mCopyingFirstPidStartUptime;
+ mCopyingFirstPidSucceeded = copySucceeded;
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+ /** Records the start of pre-dumping. */
+ public void dumpStackTracesTempFileStarted() {
+ mTempFileDumpingStartUptime = getUptimeMillis();
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dumpStackTracesTempFile");
+ }
+
+ /** Records the end of pre-dumping. */
+ public void dumpStackTracesTempFileEnded() {
+ mTempFileDumpingDuration = getUptimeMillis() - mTempFileDumpingStartUptime;
+ if (mEarlyDumpStatus == EarlyDumpStatus.UNKNOWN) {
+ mEarlyDumpStatus = EarlyDumpStatus.SUCCEEDED;
+ }
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+ /** Records file creation failure events in dumpStackTracesTempFile. */
+ public void dumpStackTracesTempFileCreationFailed() {
+ mEarlyDumpStatus = EarlyDumpStatus.FAILED_TO_CREATE_FILE;
+ Trace.instant(TRACE_TAG_ACTIVITY_MANAGER, "dumpStackTracesTempFileCreationFailed");
+ }
+
+ /** Records timeout events in dumpStackTracesTempFile. */
+ public void dumpStackTracesTempFileTimedOut() {
+ mEarlyDumpStatus = EarlyDumpStatus.TIMED_OUT;
+ Trace.instant(TRACE_TAG_ACTIVITY_MANAGER, "dumpStackTracesTempFileTimedOut");
+ }
+
+ /** Records the start of native pids dumping to file. */
public void dumpingNativePidsStarted() {
mNativePidsDumpingStartUptime = getUptimeMillis();
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dumpingNativePids");
}
- /** Records the end of pid dumping to file (subject and criticalEventSection). */
+ /** Records the end of native pids dumping to file . */
public void dumpingNativePidsEnded() {
mNativePidsDumpingDuration = getUptimeMillis() - mNativePidsDumpingStartUptime;
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
- /** Records the start of pid dumping to file (subject and criticalEventSection). */
+ /** Records the start of extra pids dumping to file. */
public void dumpingExtraPidsStarted() {
mExtraPidsDumpingStartUptime = getUptimeMillis();
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dumpingExtraPids");
}
- /** Records the end of pid dumping to file (subject and criticalEventSection). */
+ /** Records the end of extra pids dumping to file. */
public void dumpingExtraPidsEnded() {
mExtraPidsDumpingDuration = getUptimeMillis() - mExtraPidsDumpingStartUptime;
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
@@ -337,7 +415,7 @@
* Returns latency data as a comma separated value string for inclusion in ANR report.
*/
public String dumpAsCommaSeparatedArrayWithHeader() {
- return "DurationsV2: " + mAnrTriggerUptime
+ return "DurationsV3: " + mAnrTriggerUptime
/* triggering_to_app_not_responding_duration = */
+ "," + (mAppNotRespondingStartUptime - mAnrTriggerUptime)
/* app_not_responding_duration = */
@@ -370,7 +448,22 @@
/* anr_queue_size_when_pushed = */
+ "," + mAnrQueueSize
/* dump_stack_traces_io_time = */
- + "," + (mFirstPidsDumpingStartUptime - mDumpStackTracesStartUptime)
+ // We use copyingFirstPidUptime if we're dumping the durations list before the
+ // first pids ie after copying the early dump stacks.
+ + "," + ((mFirstPidsDumpingStartUptime > 0 ? mFirstPidsDumpingStartUptime
+ : mCopyingFirstPidStartUptime) - mDumpStackTracesStartUptime)
+ /* temp_file_dump_duration = */
+ + "," + mTempFileDumpingDuration
+ /* temp_dump_request_on_queue_duration = */
+ + "," + (mTempFileDumpingStartUptime - mEarlyDumpRequestSubmissionUptime)
+ /* temp_dump_pid_count_when_pushed = */
+ + "," + mEarlyDumpExecutorPidCount
+ /* first_pid_copying_time = */
+ + "," + mCopyingFirstPidDuration
+ /* early_dump_status = */
+ + "," + mEarlyDumpStatus
+ /* copying_first_pid_succeeded = */
+ + "," + (mCopyingFirstPidSucceeded ? 1 : 0)
+ "\n\n";
}
@@ -449,7 +542,7 @@
/* anr_queue_size_when_pushed = */ mAnrQueueSize,
/* anr_type = */ mAnrType,
- /* dumped_processes_count = */ mDumpedProcessesCount);
+ /* dumped_processes_count = */ mDumpedProcessesCount.get());
}
private void anrSkipped(String method) {
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/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 47e6b6e..15f70f3 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -233,6 +233,7 @@
private boolean mLastHasLeftStableInset = false;
private int mLastWindowFlags = 0;
private boolean mLastShouldAlwaysConsumeSystemBars = false;
+ private @InsetsType int mLastSuppressScrimTypes = 0;
private int mRootScrollY = 0;
@@ -1143,6 +1144,7 @@
mLastHasLeftStableInset = hasLeftStableInset;
mLastShouldAlwaysConsumeSystemBars = insets.shouldAlwaysConsumeSystemBars();
+ mLastSuppressScrimTypes = insets.getSuppressScrimTypes();
}
boolean navBarToRightEdge = isNavBarToRightEdge(mLastBottomInset, mLastRightInset);
@@ -1378,7 +1380,8 @@
return calculateBarColor(mWindow.getAttributes().flags, FLAG_TRANSLUCENT_STATUS,
mSemiTransparentBarColor, mWindow.mStatusBarColor,
appearance, APPEARANCE_LIGHT_STATUS_BARS,
- mWindow.mEnsureStatusBarContrastWhenTransparent);
+ mWindow.mEnsureStatusBarContrastWhenTransparent
+ && (mLastSuppressScrimTypes & WindowInsets.Type.statusBars()) == 0);
}
private int calculateNavigationBarColor(@Appearance int appearance) {
@@ -1386,7 +1389,7 @@
mSemiTransparentBarColor, mWindow.mNavigationBarColor,
appearance, APPEARANCE_LIGHT_NAVIGATION_BARS,
mWindow.mEnsureNavigationBarContrastWhenTransparent
- && getContext().getResources().getBoolean(R.bool.config_navBarNeedsScrim));
+ && (mLastSuppressScrimTypes & WindowInsets.Type.navigationBars()) == 0);
}
public static int calculateBarColor(int flags, int translucentFlag, int semiTransparentBarColor,
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/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index dfcde3d..4065055 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -57,6 +57,7 @@
void removeGatekeeperPasswordHandle(long gatekeeperPasswordHandle);
int getCredentialType(int userId);
int getPinLength(int userId);
+ boolean refreshStoredPinLength(int userId);
byte[] getHashFactor(in LockscreenCredential currentCredential, int userId);
void setSeparateProfileChallengeEnabled(int userId, boolean enabled, in LockscreenCredential managedUserPassword);
boolean getSeparateProfileChallengeEnabled(int userId);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 38632d1..fbad4b9 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -622,6 +622,24 @@
return PIN_LENGTH_UNAVAILABLE;
}
}
+
+ /**
+ * This method saves the pin length value to disk based on the user's auto pin
+ * confirmation flag setting. If the auto pin confirmation flag is disabled, or if the
+ * user does not have a PIN setup, or if length of PIN is less than minimum storable PIN length
+ * value, the pin length value is set to PIN_LENGTH_UNAVAILABLE. Otherwise, if the
+ * flag is enabled, the pin length value is set to the actual length of the user's PIN.
+ * @param userId user id of the user whose pin length we want to save
+ * @return true/false depending on whether PIN length has been saved or not
+ */
+ public boolean refreshStoredPinLength(int userId) {
+ try {
+ return getLockSettings().refreshStoredPinLength(userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not store PIN length on disk " + e);
+ return false;
+ }
+ }
/**
* Records that the user has chosen a pattern at some time, even if the pattern is
* currently cleared.
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/companion/OWNERS b/core/proto/android/companion/OWNERS
new file mode 100644
index 0000000..edf9e56
--- /dev/null
+++ b/core/proto/android/companion/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/companion/OWNERS
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 05b38a5..9a54500 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2917,6 +2917,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..c7395dd 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" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 947dc2d..362d859 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1970,8 +1970,8 @@
<string name="face_error_user_canceled">Face Unlock canceled by user</string>
<!-- Generic error message shown when the face operation fails because too many attempts have been made. [CHAR LIMIT=50] -->
<string name="face_error_lockout">Too many attempts. Try again later.</string>
- <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=90] -->
- <string name="face_error_lockout_permanent">Too many attempts. Face Unlock disabled.</string>
+ <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=100] -->
+ <string name="face_error_lockout_permanent">Too many attempts. Face Unlock unavailable.</string>
<!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=90] -->
<string name="face_error_lockout_screen_lock">Too many attempts. Enter screen lock instead.</string>
<!-- Generic error message shown when the face hardware can't recognize the face. [CHAR LIMIT=50] -->
@@ -5907,9 +5907,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/coretests/src/android/hardware/face/FaceManagerTest.java b/core/tests/coretests/src/android/hardware/face/FaceManagerTest.java
index 9a202ae..1075d44 100644
--- a/core/tests/coretests/src/android/hardware/face/FaceManagerTest.java
+++ b/core/tests/coretests/src/android/hardware/face/FaceManagerTest.java
@@ -21,8 +21,11 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -38,6 +41,8 @@
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
+import com.android.internal.R;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -50,6 +55,7 @@
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
@Presubmit
@@ -70,6 +76,8 @@
private IFaceService mService;
@Mock
private FaceManager.AuthenticationCallback mAuthCallback;
+ @Mock
+ private FaceManager.EnrollmentCallback mEnrollmentCallback;
@Captor
private ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> mCaptor;
@@ -107,9 +115,7 @@
@Test
public void getSensorPropertiesInternal_noBinderCalls() throws RemoteException {
- verify(mService).addAuthenticatorsRegisteredCallback(mCaptor.capture());
-
- mCaptor.getValue().onAllAuthenticatorsRegistered(mProps);
+ initializeProperties();
List<FaceSensorPropertiesInternal> actual = mFaceManager.getSensorPropertiesInternal();
assertThat(actual).containsExactlyElementsIn(mProps);
@@ -148,4 +154,33 @@
verify(mAuthCallback).onAuthenticationError(eq(FACE_ERROR_HW_UNAVAILABLE), any());
}
+
+ @Test
+ public void enrollment_errorWhenFaceEnrollmentExists() throws RemoteException {
+ when(mResources.getInteger(R.integer.config_faceMaxTemplatesPerUser)).thenReturn(1);
+ when(mService.getEnrolledFaces(anyInt(), anyInt(), anyString()))
+ .thenReturn(Collections.emptyList())
+ .thenReturn(Collections.singletonList(new Face("Face" /* name */, 0 /* faceId */,
+ 0 /* deviceId */)));
+
+ initializeProperties();
+ mFaceManager.enroll(USER_ID, new byte[]{},
+ new CancellationSignal(), mEnrollmentCallback, null /* disabledFeatures */);
+
+ verify(mService).enroll(eq(USER_ID), any(), any(), any(), anyString(), any(), any(),
+ anyBoolean());
+
+ mFaceManager.enroll(USER_ID, new byte[]{},
+ new CancellationSignal(), mEnrollmentCallback, null /* disabledFeatures */);
+
+ verify(mService, atMost(1 /* maxNumberOfInvocations */)).enroll(eq(USER_ID), any(), any(),
+ any(), anyString(), any(), any(), anyBoolean());
+ verify(mEnrollmentCallback).onEnrollmentError(eq(FACE_ERROR_HW_UNAVAILABLE), anyString());
+ }
+
+ private void initializeProperties() throws RemoteException {
+ verify(mService).addAuthenticatorsRegisteredCallback(mCaptor.capture());
+
+ mCaptor.getValue().onAllAuthenticatorsRegistered(mProps);
+ }
}
diff --git a/core/tests/coretests/src/android/internal/os/anr/AnrLatencyTrackerTests.java b/core/tests/coretests/src/android/internal/os/anr/AnrLatencyTrackerTests.java
index 4eea076..7d5a0364 100644
--- a/core/tests/coretests/src/android/internal/os/anr/AnrLatencyTrackerTests.java
+++ b/core/tests/coretests/src/android/internal/os/anr/AnrLatencyTrackerTests.java
@@ -59,7 +59,10 @@
.thenReturn(175L)
.thenReturn(198L)
.thenReturn(203L)
- .thenReturn(209L);
+ .thenReturn(209L)
+ .thenReturn(211L)
+ .thenReturn(212L)
+ .thenReturn(220L);
}
@Test
@@ -68,6 +71,7 @@
mLatencyTracker.appNotRespondingStarted();
mLatencyTracker.waitingOnAnrRecordLockStarted();
mLatencyTracker.waitingOnAnrRecordLockEnded();
+ mLatencyTracker.earlyDumpRequestSubmittedWithSize(5);
mLatencyTracker.anrRecordPlacingOnQueueWithSize(3);
mLatencyTracker.appNotRespondingEnded();
@@ -90,7 +94,16 @@
mLatencyTracker.waitingOnProcLockStarted();
mLatencyTracker.waitingOnProcLockEnded();
+ mLatencyTracker.dumpStackTracesTempFileStarted();
+ mLatencyTracker.dumpingPidStarted(5);
+
mLatencyTracker.dumpStackTracesStarted();
+ mLatencyTracker.copyingFirstPidStarted();
+
+ mLatencyTracker.dumpingPidEnded();
+ mLatencyTracker.dumpStackTracesTempFileEnded();
+
+ mLatencyTracker.copyingFirstPidEnded(true);
mLatencyTracker.dumpingFirstPidsStarted();
mLatencyTracker.dumpingPidStarted(1);
mLatencyTracker.dumpingPidEnded();
@@ -111,7 +124,7 @@
mLatencyTracker.close();
assertThat(mLatencyTracker.dumpAsCommaSeparatedArrayWithHeader())
- .isEqualTo("DurationsV2: 50,5,25,8,115,2,3,7,8,15,2,7,23,10,3,6\n\n");
+ .isEqualTo("DurationsV3: 50,5,33,11,112,4,2,4,6,5,1,10,5,10,3,9,11,129,5,8,1\n\n");
verify(mLatencyTracker, times(1)).pushAtom();
}
@@ -121,6 +134,7 @@
mLatencyTracker.appNotRespondingStarted();
mLatencyTracker.waitingOnAnrRecordLockStarted();
mLatencyTracker.waitingOnAnrRecordLockEnded();
+ mLatencyTracker.earlyDumpRequestSubmittedWithSize(5);
mLatencyTracker.anrRecordPlacingOnQueueWithSize(3);
mLatencyTracker.appNotRespondingEnded();
@@ -143,7 +157,18 @@
mLatencyTracker.waitingOnProcLockStarted();
mLatencyTracker.waitingOnProcLockEnded();
+
+
+ mLatencyTracker.dumpStackTracesTempFileStarted();
+ mLatencyTracker.dumpingPidStarted(5);
+
mLatencyTracker.dumpStackTracesStarted();
+ mLatencyTracker.copyingFirstPidStarted();
+
+ mLatencyTracker.dumpingPidEnded();
+ mLatencyTracker.dumpStackTracesTempFileEnded();
+
+ mLatencyTracker.copyingFirstPidEnded(true);
mLatencyTracker.dumpingFirstPidsStarted();
mLatencyTracker.dumpingPidStarted(1);
mLatencyTracker.dumpingPidEnded();
diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java
index 4fed396..b4ba23c 100644
--- a/core/tests/coretests/src/android/view/WindowInsetsTest.java
+++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java
@@ -40,14 +40,14 @@
@Test
public void systemWindowInsets_afterConsuming_isConsumed() {
assertTrue(new WindowInsets(WindowInsets.createCompatTypeMap(new Rect(1, 2, 3, 4)), null,
- null, false, false, null, null, null, null,
+ null, false, false, 0, null, null, null, null,
WindowInsets.Type.systemBars(), false)
.consumeSystemWindowInsets().isConsumed());
}
@Test
public void multiNullConstructor_isConsumed() {
- assertTrue(new WindowInsets(null, null, null, false, false, null, null, null, null,
+ assertTrue(new WindowInsets(null, null, null, false, false, 0, null, null, null, null,
WindowInsets.Type.systemBars(), false).isConsumed());
}
@@ -63,8 +63,8 @@
boolean[] visible = new boolean[SIZE];
WindowInsets.assignCompatInsets(maxInsets, new Rect(0, 10, 0, 0));
WindowInsets.assignCompatInsets(insets, new Rect(0, 0, 0, 0));
- WindowInsets windowInsets = new WindowInsets(insets, maxInsets, visible, false, false, null,
- null, null, DisplayShape.NONE, systemBars(),
+ WindowInsets windowInsets = new WindowInsets(insets, maxInsets, visible, false, false,
+ 0, null, null, null, DisplayShape.NONE, systemBars(),
true /* compatIgnoreVisibility */);
assertEquals(Insets.of(0, 10, 0, 0), windowInsets.getSystemWindowInsets());
}
diff --git a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
index 4d4ec35..a1a4265 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
@@ -169,7 +169,7 @@
private WindowInsets insetsWith(Insets content, DisplayCutout cutout) {
return new WindowInsets(WindowInsets.createCompatTypeMap(content.toRect()), null, null,
- false, false, cutout, null, null, null, WindowInsets.Type.systemBars(), false);
+ false, false, 0, cutout, null, null, null, WindowInsets.Type.systemBars(), false);
}
private ViewGroup createViewGroupWithId(int id) {
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 0faf62e..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"/>
@@ -515,6 +516,8 @@
<permission name="android.permission.READ_RESTRICTED_STATS"/>
<!-- Permission required for CTS test -->
<permission name="android.permission.LOG_FOREGROUND_RESOURCE_USE"/>
+ <!-- Permission required for CTS test - CtsVoiceInteractionTestCases -->
+ <permission name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
index f6b21ba..fb1980a 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
@@ -31,8 +31,7 @@
android:orientation="horizontal"
android:clickable="true"
android:focusable="true"
- android:paddingStart="8dp"
- android:background="?android:selectableItemBackgroundBorderless">
+ android:paddingStart="8dp">
<ImageView
android:id="@+id/application_icon"
@@ -88,6 +87,6 @@
android:src="@drawable/decor_close_button_dark"
android:scaleType="fitCenter"
android:gravity="end"
- android:background="?android:selectableItemBackgroundBorderless"
+ android:background="@null"
android:tint="@color/desktop_mode_caption_close_button_dark"/>
</com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file
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 026ea069..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
@@ -47,7 +47,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
-import com.android.launcher3.icons.BubbleBadgeIconFactory;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
@@ -65,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
@@ -182,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.
*/
@@ -217,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)
@@ -242,6 +275,7 @@
final Bubbles.BubbleMetadataFlagListener listener,
final Bubbles.PendingIntentCanceledListener intentCancelListener,
Executor mainExecutor) {
+ mIsAppBubble = false;
mKey = entry.getKey();
mGroupKey = entry.getGroupKey();
mLocusId = entry.getLocusId();
@@ -436,7 +470,6 @@
* @param stackView the view the bubble is added to, iff showing as floating.
* @param layerView the layer the bubble is added to, iff showing in the bubble bar.
* @param iconFactory the icon factory use to create images for the bubble.
- * @param badgeIconFactory the icon factory to create app badges for the bubble.
*/
void inflate(BubbleViewInfoTask.Callback callback,
Context context,
@@ -444,7 +477,6 @@
@Nullable BubbleStackView stackView,
@Nullable BubbleBarLayerView layerView,
BubbleIconFactory iconFactory,
- BubbleBadgeIconFactory badgeIconFactory,
boolean skipInflation) {
if (isBubbleLoading()) {
mInflationTask.cancel(true /* mayInterruptIfRunning */);
@@ -455,7 +487,6 @@
stackView,
layerView,
iconFactory,
- badgeIconFactory,
skipInflation,
callback,
mMainExecutor);
@@ -819,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 fd66153..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;
@@ -89,7 +88,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.launcher3.icons.BubbleBadgeIconFactory;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -209,7 +207,6 @@
@Nullable private BubbleStackView mStackView;
@Nullable private BubbleBarLayerView mLayerView;
private BubbleIconFactory mBubbleIconFactory;
- private BubbleBadgeIconFactory mBubbleBadgeIconFactory;
private BubblePositioner mBubblePositioner;
private Bubbles.SysuiProxy mSysuiProxy;
@@ -321,8 +318,7 @@
mBubbleData = data;
mSavedUserBubbleData = new SparseArray<>();
mBubbleIconFactory = new BubbleIconFactory(context,
- context.getResources().getDimensionPixelSize(R.dimen.bubble_size));
- mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(context,
+ context.getResources().getDimensionPixelSize(R.dimen.bubble_size),
context.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
context.getResources().getColor(R.color.important_conversation),
context.getResources().getDimensionPixelSize(
@@ -700,6 +696,10 @@
return mBubblePositioner;
}
+ BubbleIconFactory getIconFactory() {
+ return mBubbleIconFactory;
+ }
+
public Bubbles.SysuiProxy getSysuiProxy() {
return mSysuiProxy;
}
@@ -936,8 +936,7 @@
mStackView.onThemeChanged();
}
mBubbleIconFactory = new BubbleIconFactory(mContext,
- mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size));
- mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext,
+ mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size),
mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
mContext.getResources().getColor(R.color.important_conversation),
mContext.getResources().getDimensionPixelSize(
@@ -951,7 +950,6 @@
mStackView,
mLayerView,
mBubbleIconFactory,
- mBubbleBadgeIconFactory,
false /* skipInflation */);
}
for (Bubble b : mBubbleData.getOverflowBubbles()) {
@@ -961,7 +959,6 @@
mStackView,
mLayerView,
mBubbleIconFactory,
- mBubbleBadgeIconFactory,
false /* skipInflation */);
}
}
@@ -978,8 +975,7 @@
mScreenBounds.set(newConfig.windowConfiguration.getBounds());
mBubbleData.onMaxBubblesChanged();
mBubbleIconFactory = new BubbleIconFactory(mContext,
- mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size));
- mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext,
+ mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size),
mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
mContext.getResources().getColor(R.color.important_conversation),
mContext.getResources().getDimensionPixelSize(
@@ -1196,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 {
@@ -1217,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);
}
@@ -1250,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);
}
/**
@@ -1275,7 +1272,6 @@
mStackView,
mLayerView,
mBubbleIconFactory,
- mBubbleBadgeIconFactory,
true /* skipInflation */);
});
return null;
@@ -1351,7 +1347,7 @@
bubble.setInflateSynchronously(mInflateSynchronously);
bubble.inflate(b -> mBubbleData.notificationEntryUpdated(b, suppressFlyout, showInShade),
mContext, this, mStackView, mLayerView,
- mBubbleIconFactory, mBubbleBadgeIconFactory,
+ mBubbleIconFactory,
false /* skipInflation */);
}
@@ -2049,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<>();
@@ -2081,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);
}
/**
@@ -2147,7 +2144,7 @@
pw.println(" suppressing: " + key);
}
- pw.print("mAppBubbleTaskId: " + mAppBubbleTaskId);
+ pw.print("mAppBubbleTaskIds: " + mAppBubbleTaskIds.values());
}
}
@@ -2209,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 f9cf9d3..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;
@@ -38,6 +37,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.Bubbles.DismissReason;
import com.android.wm.shell.common.bubbles.BubbleBarUpdate;
@@ -779,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 a317c44..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
@@ -246,7 +246,7 @@
mBubble.getAppBubbleIntent()
.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT)
.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK),
- PendingIntent.FLAG_IMMUTABLE,
+ PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
/* options= */ null);
mTaskView.startActivity(pi, /* fillInIntent= */ null, options,
launchBounds);
@@ -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/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index c2a05b7..c49451d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -95,7 +95,11 @@
overflowBtn?.iconDrawable?.setTint(shapeColor)
val iconFactory = BubbleIconFactory(context,
- context.getResources().getDimensionPixelSize(R.dimen.bubble_size))
+ context.getResources().getDimensionPixelSize(R.dimen.bubble_size),
+ context.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
+ context.getResources().getColor(R.color.important_conversation),
+ context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.importance_ring_stroke_width))
// Update bitmap
val fg = InsetDrawable(overflowBtn?.iconDrawable, overflowIconInset)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index d1081de..8ab9841 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
@@ -42,7 +42,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.BubbleBadgeIconFactory;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
@@ -75,7 +74,6 @@
private WeakReference<BubbleStackView> mStackView;
private WeakReference<BubbleBarLayerView> mLayerView;
private BubbleIconFactory mIconFactory;
- private BubbleBadgeIconFactory mBadgeIconFactory;
private boolean mSkipInflation;
private Callback mCallback;
private Executor mMainExecutor;
@@ -90,7 +88,6 @@
@Nullable BubbleStackView stackView,
@Nullable BubbleBarLayerView layerView,
BubbleIconFactory factory,
- BubbleBadgeIconFactory badgeFactory,
boolean skipInflation,
Callback c,
Executor mainExecutor) {
@@ -100,7 +97,6 @@
mStackView = new WeakReference<>(stackView);
mLayerView = new WeakReference<>(layerView);
mIconFactory = factory;
- mBadgeIconFactory = badgeFactory;
mSkipInflation = skipInflation;
mCallback = c;
mMainExecutor = mainExecutor;
@@ -110,10 +106,10 @@
protected BubbleViewInfo doInBackground(Void... voids) {
if (mController.get().isShowingAsBubbleBar()) {
return BubbleViewInfo.populateForBubbleBar(mContext.get(), mController.get(),
- mLayerView.get(), mBadgeIconFactory, mBubble, mSkipInflation);
+ mLayerView.get(), mIconFactory, mBubble, mSkipInflation);
} else {
return BubbleViewInfo.populate(mContext.get(), mController.get(), mStackView.get(),
- mIconFactory, mBadgeIconFactory, mBubble, mSkipInflation);
+ mIconFactory, mBubble, mSkipInflation);
}
}
@@ -156,7 +152,7 @@
@Nullable
public static BubbleViewInfo populateForBubbleBar(Context c, BubbleController controller,
- BubbleBarLayerView layerView, BubbleBadgeIconFactory badgeIconFactory, Bubble b,
+ BubbleBarLayerView layerView, BubbleIconFactory iconFactory, Bubble b,
boolean skipInflation) {
BubbleViewInfo info = new BubbleViewInfo();
@@ -195,7 +191,7 @@
return null;
}
- info.rawBadgeBitmap = badgeIconFactory.getBadgeBitmap(badgedIcon, false).icon;
+ info.rawBadgeBitmap = iconFactory.getBadgeBitmap(badgedIcon, false).icon;
return info;
}
@@ -203,8 +199,7 @@
@VisibleForTesting
@Nullable
public static BubbleViewInfo populate(Context c, BubbleController controller,
- BubbleStackView stackView, BubbleIconFactory iconFactory,
- BubbleBadgeIconFactory badgeIconFactory, Bubble b,
+ BubbleStackView stackView, BubbleIconFactory iconFactory, Bubble b,
boolean skipInflation) {
BubbleViewInfo info = new BubbleViewInfo();
@@ -256,16 +251,16 @@
bubbleDrawable = appIcon;
}
- BitmapInfo badgeBitmapInfo = badgeIconFactory.getBadgeBitmap(badgedIcon,
+ BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon,
b.isImportantConversation());
info.badgeBitmap = badgeBitmapInfo.icon;
// Raw badge bitmap never includes the important conversation ring
info.rawBadgeBitmap = b.isImportantConversation()
- ? badgeIconFactory.getBadgeBitmap(badgedIcon, false).icon
+ ? iconFactory.getBadgeBitmap(badgedIcon, false).icon
: badgeBitmapInfo.icon;
float[] bubbleBitmapScale = new float[1];
- info.bubbleBitmap = iconFactory.createIconBitmap(bubbleDrawable, bubbleBitmapScale);
+ info.bubbleBitmap = iconFactory.getBubbleBitmap(bubbleDrawable, bubbleBitmapScale);
// Dot color & placement
Path iconPath = PathParser.createPathFromPathData(
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 d04ce15..713ace6 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() {
@@ -1007,6 +1011,7 @@
return;
}
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ mPipTransitionController.onFixedRotationFinished();
clearWaitForFixedRotation();
return;
}
@@ -1606,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/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 5755a10..99cb6f7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -409,9 +409,31 @@
@Override
public void onFixedRotationStarted() {
+ fadeEnteredPipIfNeed(false /* show */);
+ }
+
+ @Override
+ public void onFixedRotationFinished() {
+ fadeEnteredPipIfNeed(true /* show */);
+ }
+
+ private void fadeEnteredPipIfNeed(boolean show) {
// The transition with this fixed rotation may be handled by other handler before reaching
// PipTransition, so we cannot do this in #startAnimation.
- if (mPipTransitionState.getTransitionState() == ENTERED_PIP && !mHasFadeOut) {
+ if (!mPipTransitionState.hasEnteredPip()) {
+ return;
+ }
+ if (show && mHasFadeOut) {
+ // If there is a pending transition, then let startAnimation handle it. And if it is
+ // handled, mHasFadeOut will be set to false and this runnable will be no-op. Otherwise
+ // make sure the PiP will reshow, e.g. swipe-up with fixed rotation (fade-out) but
+ // return to the current app (only finish the recent transition).
+ mTransitions.runOnIdle(() -> {
+ if (mHasFadeOut && mPipTransitionState.hasEnteredPip()) {
+ fadeExistingPip(true /* show */);
+ }
+ });
+ } else if (!show && !mHasFadeOut) {
// Fade out the existing PiP to avoid jump cut during seamless rotation.
fadeExistingPip(false /* show */);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index ff7ab8b..949d6f5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -123,6 +123,10 @@
public void onFixedRotationStarted() {
}
+ /** Called when the fixed rotation finished. */
+ public void onFixedRotationFinished() {
+ }
+
public PipTransitionController(
@NonNull ShellInit shellInit,
@NonNull ShellTaskOrganizer shellTaskOrganizer,
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 c8d6a5e8..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();
}
@@ -540,20 +535,25 @@
mergeActivityOnly(info, t);
} else if (!didMergeThings) {
// Didn't recognize anything in incoming transition so don't merge it.
- Slog.w(TAG, "Don't know how to merge this transition.");
+ Slog.w(TAG, "Don't know how to merge this transition, foundRecentsClosing="
+ + foundRecentsClosing);
+ if (foundRecentsClosing) {
+ mWillFinishToHome = false;
+ cancel(false /* toHome */);
+ }
return;
}
// At this point, we are accepting the merge.
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 5226eee..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
@@ -335,7 +335,8 @@
@Override
public boolean onTouch(View v, MotionEvent e) {
final int id = v.getId();
- if (id != R.id.caption_handle && id != R.id.desktop_mode_caption) {
+ if (id != R.id.caption_handle && id != R.id.desktop_mode_caption
+ && id != R.id.open_menu_button && id != R.id.close_window) {
return false;
}
moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));
@@ -780,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/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
index 78cfcbd..b67acd5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
@@ -35,7 +35,9 @@
captionView.setOnTouchListener(onCaptionTouchListener)
captionHandle.setOnTouchListener(onCaptionTouchListener)
openMenuButton.setOnClickListener(onCaptionButtonClickListener)
+ openMenuButton.setOnTouchListener(onCaptionTouchListener)
closeWindowButton.setOnClickListener(onCaptionButtonClickListener)
+ closeWindowButton.setOnTouchListener(onCaptionTouchListener)
appNameTextView.text = appName
appIconImageView.setImageDrawable(appIcon)
}
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/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 1a47db5..da4f66d 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -293,8 +293,10 @@
// with the same canvas transformation + clip into the target
// canvas then draw the layer on top
if (renderNode->hasHolePunches()) {
+ canvas->save();
TransformCanvas transformCanvas(canvas, SkBlendMode::kDstOut);
displayList->draw(&transformCanvas);
+ canvas->restore();
}
canvas->drawImageRect(snapshotImage, SkRect::Make(srcBounds),
SkRect::Make(dstBounds), sampling, &paint,
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 3123ee6..e73cf87 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1237,9 +1237,6 @@
public static final Set<Integer> DEVICE_IN_ALL_SCO_SET;
/** @hide */
public static final Set<Integer> DEVICE_IN_ALL_USB_SET;
- /** @hide */
- public static final Set<Integer> DEVICE_IN_ALL_BLE_SET;
-
static {
DEVICE_IN_ALL_SET = new HashSet<>();
DEVICE_IN_ALL_SET.add(DEVICE_IN_COMMUNICATION);
@@ -1279,66 +1276,6 @@
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_ACCESSORY);
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_DEVICE);
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_HEADSET);
-
- DEVICE_IN_ALL_BLE_SET = new HashSet<>();
- DEVICE_IN_ALL_BLE_SET.add(DEVICE_IN_BLE_HEADSET);
- }
-
- /** @hide */
- public static boolean isBluetoothDevice(int deviceType) {
- return isBluetoothA2dpOutDevice(deviceType)
- || isBluetoothScoDevice(deviceType)
- || isBluetoothLeDevice(deviceType);
- }
-
- /** @hide */
- public static boolean isBluetoothOutDevice(int deviceType) {
- return isBluetoothA2dpOutDevice(deviceType)
- || isBluetoothScoOutDevice(deviceType)
- || isBluetoothLeOutDevice(deviceType);
- }
-
- /** @hide */
- public static boolean isBluetoothInDevice(int deviceType) {
- return isBluetoothScoInDevice(deviceType)
- || isBluetoothLeInDevice(deviceType);
- }
-
- /** @hide */
- public static boolean isBluetoothA2dpOutDevice(int deviceType) {
- return DEVICE_OUT_ALL_A2DP_SET.contains(deviceType);
- }
-
- /** @hide */
- public static boolean isBluetoothScoOutDevice(int deviceType) {
- return DEVICE_OUT_ALL_SCO_SET.contains(deviceType);
- }
-
- /** @hide */
- public static boolean isBluetoothScoInDevice(int deviceType) {
- return DEVICE_IN_ALL_SCO_SET.contains(deviceType);
- }
-
- /** @hide */
- public static boolean isBluetoothScoDevice(int deviceType) {
- return isBluetoothScoOutDevice(deviceType)
- || isBluetoothScoInDevice(deviceType);
- }
-
- /** @hide */
- public static boolean isBluetoothLeOutDevice(int deviceType) {
- return DEVICE_OUT_ALL_BLE_SET.contains(deviceType);
- }
-
- /** @hide */
- public static boolean isBluetoothLeInDevice(int deviceType) {
- return DEVICE_IN_ALL_BLE_SET.contains(deviceType);
- }
-
- /** @hide */
- public static boolean isBluetoothLeDevice(int deviceType) {
- return isBluetoothLeOutDevice(deviceType)
- || isBluetoothLeInDevice(deviceType);
}
/** @hide */
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/SettingsProvider/src/android/provider/settings/OWNERS b/packages/SettingsProvider/src/android/provider/settings/OWNERS
index 0f88811..d901e2c 100644
--- a/packages/SettingsProvider/src/android/provider/settings/OWNERS
+++ b/packages/SettingsProvider/src/android/provider/settings/OWNERS
@@ -1,4 +1,4 @@
# Bug component: 656484
-include platform/frameworks/base:/services/backup/OWNERS
+include platform/frameworks/base:/services/backup/BACKUP_OWNERS
diff --git a/packages/SettingsProvider/test/src/android/provider/OWNERS b/packages/SettingsProvider/test/src/android/provider/OWNERS
index 0f88811..db4b27c 100644
--- a/packages/SettingsProvider/test/src/android/provider/OWNERS
+++ b/packages/SettingsProvider/test/src/android/provider/OWNERS
@@ -1,4 +1,3 @@
# Bug component: 656484
-include platform/frameworks/base:/services/backup/OWNERS
-
+include platform/frameworks/base:/services/backup/BACKUP_OWNERS
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index a202e16..706666c 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -449,6 +449,7 @@
Settings.Global.SHOW_PEOPLE_SPACE,
Settings.Global.SHOW_NEW_NOTIF_DISMISS,
Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
+ Settings.Global.SHOW_TARE_DEVELOPER_OPTIONS,
Settings.Global.SHOW_TEMPERATURE_WARNING,
Settings.Global.SHOW_USB_TEMPERATURE_ALARM,
Settings.Global.SIGNED_CONFIG_VERSION,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 78d93bd..751fbaa 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -634,6 +634,9 @@
<uses-permission android:name="android.permission.MANAGE_HOTWORD_DETECTION" />
<uses-permission android:name="android.permission.BIND_HOTWORD_DETECTION_SERVICE" />
+ <!-- Permission required for CTS test - CtsVoiceInteractionTestCases -->
+ <uses-permission android:name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER"/>
+
<uses-permission android:name="android.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE" />
<!-- Permission required for CTS test - KeyguardLockedStateApiTest -->
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
index 3eb7fd8..23f16f2 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
@@ -18,6 +18,7 @@
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.fonts.Font
+import android.graphics.fonts.FontVariationAxis
import android.graphics.text.PositionedGlyphs
import android.text.Layout
import android.text.TextPaint
@@ -211,8 +212,15 @@
run.baseX[i] = MathUtils.lerp(run.baseX[i], run.targetX[i], progress)
run.baseY[i] = MathUtils.lerp(run.baseY[i], run.targetY[i], progress)
}
- run.fontRuns.forEach {
- it.baseFont = fontInterpolator.lerp(it.baseFont, it.targetFont, progress)
+ run.fontRuns.forEach { fontRun ->
+ fontRun.baseFont =
+ fontInterpolator.lerp(fontRun.baseFont, fontRun.targetFont, progress)
+ val tmpFontVariationsArray = mutableListOf<FontVariationAxis>()
+ fontRun.baseFont.axes.forEach {
+ tmpFontVariationsArray.add(FontVariationAxis(it.tag, it.styleValue))
+ }
+ basePaint.fontVariationSettings =
+ FontVariationAxis.toFontVariationSettings(tmpFontVariationsArray)
}
}
}
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/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index eaf3229..34adcc7 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -32,6 +32,12 @@
import com.android.systemui.plugins.PluginLifecycleManager
import com.android.systemui.plugins.PluginListener
import com.android.systemui.plugins.PluginManager
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogMessage
+import com.android.systemui.plugins.log.LogMessageImpl
+import com.android.systemui.plugins.log.MessageInitializer
+import com.android.systemui.plugins.log.MessagePrinter
import com.android.systemui.util.Assert
import java.io.PrintWriter
import java.util.concurrent.ConcurrentHashMap
@@ -40,7 +46,6 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
-private const val DEBUG = true
private val KEY_TIMESTAMP = "appliedTimestamp"
private fun <TKey, TVal> ConcurrentHashMap<TKey, TVal>.concurrentGetOrPut(
@@ -55,6 +60,32 @@
return result ?: value
}
+private val TMP_MESSAGE: LogMessage by lazy { LogMessageImpl.Factory.create() }
+
+private inline fun LogBuffer?.tryLog(
+ tag: String,
+ level: LogLevel,
+ messageInitializer: MessageInitializer,
+ noinline messagePrinter: MessagePrinter,
+ ex: Throwable? = null,
+) {
+ if (this != null) {
+ // Wrap messagePrinter to convert it from crossinline to noinline
+ this.log(tag, level, messageInitializer, messagePrinter, ex)
+ } else {
+ messageInitializer(TMP_MESSAGE)
+ val msg = messagePrinter(TMP_MESSAGE)
+ when (level) {
+ LogLevel.VERBOSE -> Log.v(tag, msg, ex)
+ LogLevel.DEBUG -> Log.d(tag, msg, ex)
+ LogLevel.INFO -> Log.i(tag, msg, ex)
+ LogLevel.WARNING -> Log.w(tag, msg, ex)
+ LogLevel.ERROR -> Log.e(tag, msg, ex)
+ LogLevel.WTF -> Log.wtf(tag, msg, ex)
+ }
+ }
+}
+
/** ClockRegistry aggregates providers and plugins */
open class ClockRegistry(
val context: Context,
@@ -66,8 +97,9 @@
val handleAllUsers: Boolean,
defaultClockProvider: ClockProvider,
val fallbackClockId: ClockId = DEFAULT_CLOCK_ID,
+ val logBuffer: LogBuffer? = null,
val keepAllLoaded: Boolean,
- val subTag: String,
+ subTag: String,
) {
private val TAG = "${ClockRegistry::class.simpleName} ($subTag)"
interface ClockChangeListener {
@@ -113,9 +145,11 @@
}
if (manager != info.manager) {
- Log.e(
+ logBuffer.tryLog(
TAG,
- "Clock Id conflict on load: $id is registered to another provider"
+ LogLevel.ERROR,
+ { str1 = id },
+ { "Clock Id conflict on load: $str1 is double registered" }
)
continue
}
@@ -138,9 +172,11 @@
val id = clock.clockId
val info = availableClocks[id]
if (info?.manager != manager) {
- Log.e(
+ logBuffer.tryLog(
TAG,
- "Clock Id conflict on unload: $id is registered to another provider"
+ LogLevel.ERROR,
+ { str1 = id },
+ { "Clock Id conflict on unload: $str1 is double registered" }
)
continue
}
@@ -211,7 +247,7 @@
ClockSettings.deserialize(json)
} catch (ex: Exception) {
- Log.e(TAG, "Failed to parse clock settings", ex)
+ logBuffer.tryLog(TAG, LogLevel.ERROR, {}, { "Failed to parse clock settings" }, ex)
null
}
settings = result
@@ -240,7 +276,7 @@
)
}
} catch (ex: Exception) {
- Log.e(TAG, "Failed to set clock settings", ex)
+ logBuffer.tryLog(TAG, LogLevel.ERROR, {}, { "Failed to set clock settings" }, ex)
}
settings = value
}
@@ -400,46 +436,55 @@
}
private fun onConnected(clockId: ClockId) {
- if (DEBUG) {
- Log.i(TAG, "Connected $clockId")
- }
-
+ logBuffer.tryLog(TAG, LogLevel.DEBUG, { str1 = clockId }, { "Connected $str1" })
if (currentClockId == clockId) {
- if (DEBUG) {
- Log.i(TAG, "Current clock ($clockId) was connected")
- }
+ logBuffer.tryLog(
+ TAG,
+ LogLevel.INFO,
+ { str1 = clockId },
+ { "Current clock ($str1) was connected" }
+ )
}
}
private fun onLoaded(clockId: ClockId) {
- if (DEBUG) {
- Log.i(TAG, "Loaded $clockId")
- }
+ logBuffer.tryLog(TAG, LogLevel.DEBUG, { str1 = clockId }, { "Loaded $str1" })
if (currentClockId == clockId) {
- Log.i(TAG, "Current clock ($clockId) was loaded")
+ logBuffer.tryLog(
+ TAG,
+ LogLevel.INFO,
+ { str1 = clockId },
+ { "Current clock ($str1) was loaded" }
+ )
triggerOnCurrentClockChanged()
}
}
private fun onUnloaded(clockId: ClockId) {
- if (DEBUG) {
- Log.i(TAG, "Unloaded $clockId")
- }
+ logBuffer.tryLog(TAG, LogLevel.DEBUG, { str1 = clockId }, { "Unloaded $str1" })
if (currentClockId == clockId) {
- Log.w(TAG, "Current clock ($clockId) was unloaded")
+ logBuffer.tryLog(
+ TAG,
+ LogLevel.WARNING,
+ { str1 = clockId },
+ { "Current clock ($str1) was unloaded" }
+ )
triggerOnCurrentClockChanged()
}
}
private fun onDisconnected(clockId: ClockId) {
- if (DEBUG) {
- Log.i(TAG, "Disconnected $clockId")
- }
+ logBuffer.tryLog(TAG, LogLevel.DEBUG, { str1 = clockId }, { "Disconnected $str1" })
if (currentClockId == clockId) {
- Log.w(TAG, "Current clock ($clockId) was disconnected")
+ logBuffer.tryLog(
+ TAG,
+ LogLevel.WARNING,
+ { str1 = clockId },
+ { "Current clock ($str1) was disconnected" }
+ )
}
}
@@ -466,12 +511,27 @@
if (isEnabled && clockId.isNotEmpty()) {
val clock = createClock(clockId)
if (clock != null) {
- if (DEBUG) {
- Log.i(TAG, "Rendering clock $clockId")
- }
+ logBuffer.tryLog(
+ TAG,
+ LogLevel.INFO,
+ { str1 = clockId },
+ { "Rendering clock $str1" }
+ )
return clock
+ } else if (availableClocks.containsKey(clockId)) {
+ logBuffer.tryLog(
+ TAG,
+ LogLevel.WARNING,
+ { str1 = clockId },
+ { "Clock $str1 not loaded; using default" }
+ )
} else {
- Log.e(TAG, "Clock $clockId not found; using default")
+ logBuffer.tryLog(
+ TAG,
+ LogLevel.ERROR,
+ { str1 = clockId },
+ { "Clock $str1 not found; using default" }
+ )
}
}
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/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt
new file mode 100644
index 0000000..8f8bff8
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt
@@ -0,0 +1,23 @@
+package com.android.systemui.shared.condition
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.launch
+
+/** Converts a boolean flow to a [Condition] object which can be used with a [Monitor] */
+@JvmOverloads
+fun Flow<Boolean>.toCondition(scope: CoroutineScope, initialValue: Boolean? = null): Condition {
+ return object : Condition(initialValue, false) {
+ var job: Job? = null
+
+ override fun start() {
+ job = scope.launch { collect { updateCondition(it) } }
+ }
+
+ override fun stop() {
+ job?.cancel()
+ job = null
+ }
+ }
+}
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/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
index 7661b8d..281067d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
@@ -23,8 +23,8 @@
import androidx.annotation.Nullable;
import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeExpansionStateManager;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -178,7 +178,7 @@
* Registers the CentralSurfaces to which this Keyguard View is mounted.
*/
void registerCentralSurfaces(CentralSurfaces centralSurfaces,
- NotificationPanelViewController notificationPanelViewController,
+ ShadeViewController shadeViewController,
@Nullable ShadeExpansionStateManager shadeExpansionStateManager,
BiometricUnlockController biometricUnlockController,
View notificationContainer,
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
index cde8ff7..6740375 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java
@@ -27,7 +27,9 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.log.dagger.KeyguardClockLog;
import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.shared.clocks.ClockRegistry;
import com.android.systemui.shared.clocks.DefaultClockProvider;
@@ -51,7 +53,8 @@
@Background CoroutineDispatcher bgDispatcher,
FeatureFlags featureFlags,
@Main Resources resources,
- LayoutInflater layoutInflater) {
+ LayoutInflater layoutInflater,
+ @KeyguardClockLog LogBuffer logBuffer) {
ClockRegistry registry = new ClockRegistry(
context,
pluginManager,
@@ -62,6 +65,7 @@
/* handleAllUsers= */ true,
new DefaultClockProvider(context, layoutInflater, resources),
context.getString(R.string.lockscreen_clock_id_fallback),
+ logBuffer,
/* keepAllLoaded = */ false,
/* subTag = */ "System");
registry.registerListeners();
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java
index d01c98a..91dd1d6 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java
@@ -17,7 +17,7 @@
package com.android.keyguard.dagger;
import com.android.keyguard.KeyguardStatusViewController;
-import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.shade.ShadeViewStateProvider;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController;
@@ -37,8 +37,8 @@
interface Factory {
KeyguardStatusBarViewComponent build(
@BindsInstance KeyguardStatusBarView view,
- @BindsInstance NotificationPanelViewController.NotificationPanelViewStateProvider
- notificationPanelViewStateProvider);
+ @BindsInstance ShadeViewStateProvider
+ shadeViewStateProvider);
}
/** Builds a {@link KeyguardStatusViewController}. */
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt
new file mode 100644
index 0000000..ae9f57f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.accessibility.data.repository
+
+import android.view.accessibility.AccessibilityManager
+import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import dagger.Module
+import dagger.Provides
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+
+/** Exposes accessibility-related state. */
+interface AccessibilityRepository {
+ /** @see [AccessibilityManager.isTouchExplorationEnabled] */
+ val isTouchExplorationEnabled: Flow<Boolean>
+
+ companion object {
+ operator fun invoke(a11yManager: AccessibilityManager): AccessibilityRepository =
+ AccessibilityRepositoryImpl(a11yManager)
+ }
+}
+
+private class AccessibilityRepositoryImpl(
+ manager: AccessibilityManager,
+) : AccessibilityRepository {
+ override val isTouchExplorationEnabled: Flow<Boolean> =
+ conflatedCallbackFlow {
+ val listener = TouchExplorationStateChangeListener(::trySend)
+ manager.addTouchExplorationStateChangeListener(listener)
+ trySend(manager.isTouchExplorationEnabled)
+ awaitClose { manager.removeTouchExplorationStateChangeListener(listener) }
+ }
+ .distinctUntilChanged()
+}
+
+@Module
+object AccessibilityRepositoryModule {
+ @Provides fun provideRepo(manager: AccessibilityManager) = AccessibilityRepository(manager)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/domain/interactor/AccessibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/accessibility/domain/interactor/AccessibilityInteractor.kt
new file mode 100644
index 0000000..968ce0d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/domain/interactor/AccessibilityInteractor.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.accessibility.domain.interactor
+
+import com.android.systemui.accessibility.data.repository.AccessibilityRepository
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+@SysUISingleton
+class AccessibilityInteractor
+@Inject
+constructor(
+ private val a11yRepo: AccessibilityRepository,
+) {
+ /** @see [android.view.accessibility.AccessibilityManager.isTouchExplorationEnabled] */
+ val isTouchExplorationEnabled: Flow<Boolean>
+ get() = a11yRepo.isTouchExplorationEnabled
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
index 7f5a67f..57ffd24 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
@@ -19,6 +19,8 @@
import android.content.Context
import android.hardware.biometrics.BiometricAuthenticator.Modality
import android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE
+import android.hardware.biometrics.BiometricConstants
+import android.hardware.face.FaceManager
import android.util.AttributeSet
import com.android.systemui.R
@@ -27,6 +29,7 @@
context: Context,
attrs: AttributeSet?
) : AuthBiometricFingerprintView(context, attrs) {
+ var isFaceClass3 = false
constructor (context: Context) : this(context, null)
@@ -34,10 +37,22 @@
override fun forceRequireConfirmation(@Modality modality: Int) = modality == TYPE_FACE
- override fun ignoreUnsuccessfulEventsFrom(@Modality modality: Int) = modality == TYPE_FACE
+ override fun ignoreUnsuccessfulEventsFrom(@Modality modality: Int, unsuccessfulReason: String) =
+ modality == TYPE_FACE && !(isFaceClass3 && isLockoutErrorString(unsuccessfulReason))
override fun onPointerDown(failedModalities: Set<Int>) = failedModalities.contains(TYPE_FACE)
override fun createIconController(): AuthIconController =
AuthBiometricFingerprintAndFaceIconController(mContext, mIconView, mIconViewOverlay)
+
+ private fun isLockoutErrorString(unsuccessfulReason: String) =
+ unsuccessfulReason == FaceManager.getErrorString(
+ mContext,
+ BiometricConstants.BIOMETRIC_ERROR_LOCKOUT,
+ 0 /*vendorCode */
+ ) || unsuccessfulReason == FaceManager.getErrorString(
+ mContext,
+ BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT,
+ 0 /*vendorCode */
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index 13bb6d3..e04dd06 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -258,7 +258,8 @@
}
/** Ignore all events from this (secondary) modality except successful authentication. */
- protected boolean ignoreUnsuccessfulEventsFrom(@Modality int modality) {
+ protected boolean ignoreUnsuccessfulEventsFrom(@Modality int modality,
+ String unsuccessfulReason) {
return false;
}
@@ -541,7 +542,7 @@
*/
public void onAuthenticationFailed(
@Modality int modality, @Nullable String failureReason) {
- if (ignoreUnsuccessfulEventsFrom(modality)) {
+ if (ignoreUnsuccessfulEventsFrom(modality, failureReason)) {
return;
}
@@ -556,7 +557,7 @@
* @param error message
*/
public void onError(@Modality int modality, String error) {
- if (ignoreUnsuccessfulEventsFrom(modality)) {
+ if (ignoreUnsuccessfulEventsFrom(modality, error)) {
return;
}
@@ -586,7 +587,7 @@
* @param help message
*/
public void onHelp(@Modality int modality, String help) {
- if (ignoreUnsuccessfulEventsFrom(modality)) {
+ if (ignoreUnsuccessfulEventsFrom(modality, help)) {
return;
}
if (mSize != AuthDialog.SIZE_MEDIUM) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 517f94f..aeebb01 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -18,6 +18,7 @@
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
+import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_BIOMETRIC_PROMPT_TRANSITION;
@@ -383,6 +384,8 @@
fingerprintAndFaceView.setSensorProperties(fpProperties);
fingerprintAndFaceView.setScaleFactorProvider(config.mScaleProvider);
fingerprintAndFaceView.updateOverrideIconLayoutParamsSize();
+ fingerprintAndFaceView.setFaceClass3(
+ faceProperties.sensorStrength == STRENGTH_STRONG);
mBiometricView = fingerprintAndFaceView;
} else if (fpProperties != null) {
final AuthBiometricFingerprintView fpView =
@@ -877,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/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 0999229..6eb3c70 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -1349,7 +1349,7 @@
default void onEnrollmentsChanged(@Modality int modality) {}
/**
- * Called when UDFPS enrollments have changed. This is called after boot and on changes to
+ * Called when enrollments have changed. This is called after boot and on changes to
* enrollment.
*/
default void onEnrollmentsChanged(
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
index 6670108..08e1e9a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
@@ -26,9 +26,6 @@
void onSuccessfulUnlock();
/** */
- void onNotificationActive();
-
- /** */
void setShowingAod(boolean showingAod);
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
index cc25368..f335d1d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
@@ -25,10 +25,6 @@
}
@Override
- public void onNotificationActive() {
- }
-
- @Override
public void setShowingAod(boolean showingAod) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
index 8bdef13..6a021f6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -174,10 +174,6 @@
}
@Override
- public void onNotificationActive() {
- }
-
- @Override
public void setShowingAod(boolean showingAod) {
mShowingAod = showingAod;
updateSessionActive();
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 ac91665..75f70ae 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -29,6 +29,7 @@
import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.accessibility.AccessibilityModule;
+import com.android.systemui.accessibility.data.repository.AccessibilityRepositoryModule;
import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
import com.android.systemui.biometrics.AlternateUdfpsTouchProvider;
@@ -47,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;
@@ -63,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;
@@ -140,6 +141,7 @@
*/
@Module(includes = {
AccessibilityModule.class,
+ AccessibilityRepositoryModule.class,
AppOpsModule.class,
AssistModule.class,
BiometricsModule.class,
@@ -167,6 +169,7 @@
PolicyModule.class,
PrivacyModule.class,
QRCodeScannerModule.class,
+ QSFragmentStartableModule.class,
ScreenshotModule.class,
SensorModule.class,
SecurityRepositoryModule.class,
@@ -196,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/dreams/touch/ShadeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/ShadeTouchHandler.java
index 58b70b0..99451f2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/ShadeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/ShadeTouchHandler.java
@@ -23,7 +23,7 @@
import android.view.GestureDetector;
import android.view.MotionEvent;
-import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import java.util.Optional;
@@ -54,8 +54,8 @@
}
session.registerInputListener(ev -> {
- final NotificationPanelViewController viewController =
- mSurfaces.map(CentralSurfaces::getNotificationPanelViewController).orElse(null);
+ final ShadeViewController viewController =
+ mSurfaces.map(CentralSurfaces::getShadeViewController).orElse(null);
if (viewController != null) {
viewController.handleExternalTouch((MotionEvent) ev);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/BouncerSwipeModule.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/BouncerSwipeModule.java
index 081bab0..5f03743 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/BouncerSwipeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/BouncerSwipeModule.java
@@ -25,16 +25,16 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.touch.BouncerSwipeTouchHandler;
import com.android.systemui.dreams.touch.DreamTouchHandler;
-import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.wm.shell.animation.FlingAnimationUtils;
-import javax.inject.Named;
-import javax.inject.Provider;
-
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoSet;
+import javax.inject.Named;
+import javax.inject.Provider;
+
/**
* This module captures the components associated with {@link BouncerSwipeTouchHandler}.
*/
@@ -78,8 +78,8 @@
return flingAnimationUtilsBuilderProvider.get()
.reset()
.setMaxLengthSeconds(
- NotificationPanelViewController.FLING_CLOSING_MAX_LENGTH_SECONDS)
- .setSpeedUpFactor(NotificationPanelViewController.FLING_SPEED_UP_FACTOR)
+ ShadeViewController.FLING_CLOSING_MAX_LENGTH_SECONDS)
+ .setSpeedUpFactor(ShadeViewController.FLING_SPEED_UP_FACTOR)
.build();
}
@@ -92,8 +92,8 @@
Provider<FlingAnimationUtils.Builder> flingAnimationUtilsBuilderProvider) {
return flingAnimationUtilsBuilderProvider.get()
.reset()
- .setMaxLengthSeconds(NotificationPanelViewController.FLING_MAX_LENGTH_SECONDS)
- .setSpeedUpFactor(NotificationPanelViewController.FLING_SPEED_UP_FACTOR)
+ .setMaxLengthSeconds(ShadeViewController.FLING_MAX_LENGTH_SECONDS)
+ .setSpeedUpFactor(ShadeViewController.FLING_SPEED_UP_FACTOR)
.build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index bd982c6..29c63bb 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -58,12 +58,6 @@
"notification_drag_to_contents"
)
- // TODO(b/254512517): Tracking Bug
- val FSI_REQUIRES_KEYGUARD = releasedFlag(110, "fsi_requires_keyguard")
-
- // TODO(b/259130119): Tracking Bug
- val FSI_ON_DND_UPDATE = releasedFlag(259130119, "fsi_on_dnd_update")
-
// TODO(b/254512538): Tracking Bug
val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply")
@@ -74,31 +68,15 @@
val NOTIFICATION_MEMORY_LOGGING_ENABLED =
unreleasedFlag(119, "notification_memory_logging_enabled")
- // TODO(b/254512731): Tracking Bug
- @JvmField val NOTIFICATION_DISMISSAL_FADE = releasedFlag(113, "notification_dismissal_fade")
-
@JvmField val USE_ROUNDNESS_SOURCETYPES = releasedFlag(116, "use_roundness_sourcetype")
- // TODO(b/259217907)
- @JvmField
- val NOTIFICATION_GROUP_DISMISSAL_ANIMATION =
- releasedFlag(259217907, "notification_group_dismissal_animation")
-
@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")
- // TODO(b/260335638): Tracking Bug
- @JvmField
- val NOTIFICATION_INLINE_REPLY_ANIMATION =
- releasedFlag(174148361, "notification_inline_reply_animation")
-
- val FILTER_UNSEEN_NOTIFS_ON_KEYGUARD =
- releasedFlag(254647461, "filter_unseen_notifs_on_keyguard")
-
// TODO(b/277338665): Tracking Bug
@JvmField
val NOTIFICATION_SHELF_REFACTOR =
@@ -329,8 +307,7 @@
unreleasedFlag(611, "new_status_bar_icons_debug_coloring")
// TODO(b/265892345): Tracking Bug
- val PLUG_IN_STATUS_BAR_CHIP =
- unreleasedFlag(265892345, "plug_in_status_bar_chip", teamfood = true)
+ val PLUG_IN_STATUS_BAR_CHIP = releasedFlag(265892345, "plug_in_status_bar_chip")
// 700 - dialer/calls
// TODO(b/254512734): Tracking Bug
@@ -406,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")
@@ -614,8 +591,6 @@
@JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag(1701, "clipboard_remote_behavior")
// 1800 - shade container
- @JvmField
- val LEAVE_SHADE_OPEN_FOR_BUGREPORT = releasedFlag(1800, "leave_shade_open_for_bugreport")
// TODO(b/265944639): Tracking Bug
@JvmField val DUAL_SHADE = unreleasedFlag(1801, "dual_shade")
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/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 4be47ec..d3b6fc2 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -1043,9 +1043,6 @@
Log.w(TAG, "Bugreport handler could not be launched");
mIActivityManager.requestInteractiveBugReport();
}
- // Maybe close shade (depends on a flag) so user sees the activity
- mCentralSurfacesOptional.ifPresent(
- CentralSurfaces::collapseShadeForBugreport);
} catch (RemoteException e) {
}
}
@@ -1064,8 +1061,6 @@
mMetricsLogger.action(MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
mUiEventLogger.log(GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS);
mIActivityManager.requestFullBugReport();
- // Maybe close shade (depends on a flag) so user sees the activity
- mCentralSurfacesOptional.ifPresent(CentralSurfaces::collapseShadeForBugreport);
} catch (RemoteException e) {
}
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0fd479a..e0af5ce 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -134,9 +134,9 @@
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeExpansionStateManager;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -3098,7 +3098,7 @@
* @return the View Controller for the Keyguard View this class is mediating.
*/
public KeyguardViewController registerCentralSurfaces(CentralSurfaces centralSurfaces,
- NotificationPanelViewController panelView,
+ ShadeViewController panelView,
@Nullable ShadeExpansionStateManager shadeExpansionStateManager,
BiometricUnlockController biometricUnlockController,
View notificationContainer, KeyguardBypassController bypassController) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
index 09002fd..0055f9a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
@@ -212,14 +212,9 @@
userId: Int,
hasEnrollments: Boolean
) {
- // TODO(b/242022358), use authController.isFaceAuthEnrolled after
- // ag/20176811 is available.
- if (
- sensorBiometricType == BiometricType.FACE &&
- userId == selectedUserId
- ) {
+ if (sensorBiometricType == BiometricType.FACE) {
trySendWithFailureLogging(
- hasEnrollments,
+ authController.isFaceAuthEnrolled(selectedUserId),
TAG,
"Face enrollment changed"
)
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/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/media/controls/models/player/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
index 1c8bfd1..8b74263 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
@@ -147,6 +147,7 @@
val expandedBottomActionIds =
setOf(
+ R.id.media_progress_bar,
R.id.actionPrev,
R.id.actionNext,
R.id.action0,
@@ -155,7 +156,22 @@
R.id.action3,
R.id.action4,
R.id.media_scrubbing_elapsed_time,
- R.id.media_scrubbing_total_time
+ R.id.media_scrubbing_total_time,
+ )
+
+ val detailIds =
+ setOf(
+ R.id.header_title,
+ R.id.header_artist,
+ R.id.media_explicit_indicator,
+ R.id.actionPlayPause,
+ )
+
+ val backgroundIds =
+ setOf(
+ R.id.album_art,
+ R.id.turbulence_noise_view,
+ R.id.touch_ripple_view,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt
index 2509f21..35f5a8c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt
@@ -20,12 +20,14 @@
import android.media.session.MediaController
import android.media.session.PlaybackState
import android.os.SystemClock
+import android.os.Trace
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
import android.widget.SeekBar
import androidx.annotation.AnyThread
+import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread
import androidx.core.view.GestureDetectorCompat
import androidx.lifecycle.LiveData
@@ -36,10 +38,13 @@
import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.util.concurrency.RepeatableExecutor
import javax.inject.Inject
+import kotlin.math.abs
private const val POSITION_UPDATE_INTERVAL_MILLIS = 100L
private const val MIN_FLING_VELOCITY_SCALE_FACTOR = 10
+private const val TRACE_POSITION_NAME = "SeekBarPollingPosition"
+
private fun PlaybackState.isInMotion(): Boolean {
return this.state == PlaybackState.STATE_PLAYING ||
this.state == PlaybackState.STATE_FAST_FORWARDING ||
@@ -295,14 +300,20 @@
@WorkerThread
private fun checkIfPollingNeeded() {
val needed = listening && !scrubbing && playbackState?.isInMotion() ?: false
+ val traceCookie = controller?.sessionToken.hashCode()
if (needed) {
if (cancel == null) {
- cancel =
+ Trace.beginAsyncSection(TRACE_POSITION_NAME, traceCookie)
+ val cancelPolling =
bgExecutor.executeRepeatedly(
this::checkPlaybackPosition,
0L,
POSITION_UPDATE_INTERVAL_MILLIS
)
+ cancel = Runnable {
+ cancelPolling.run()
+ Trace.endAsyncSection(TRACE_POSITION_NAME, traceCookie)
+ }
}
} else {
cancel?.run()
@@ -316,6 +327,10 @@
return SeekBarChangeListener(this, falsingManager)
}
+ /** first and last motion events of seekbar grab. */
+ @VisibleForTesting var firstMotionEvent: MotionEvent? = null
+ @VisibleForTesting var lastMotionEvent: MotionEvent? = null
+
/** Attach touch handlers to the seek bar view. */
fun attachTouchHandlers(bar: SeekBar) {
bar.setOnSeekBarChangeListener(seekBarListener)
@@ -342,6 +357,23 @@
}
}
+ /**
+ * This method specifies if user made a bad seekbar grab or not. If the vertical distance from
+ * first touch on seekbar is more than the horizontal distance, this means that the seekbar grab
+ * is more vertical and should be rejected. Seekbar accepts horizontal grabs only.
+ *
+ * Single tap has the same first and last motion event, it is counted as a valid grab.
+ *
+ * @return whether the touch on seekbar is valid.
+ */
+ private fun isValidSeekbarGrab(): Boolean {
+ if (firstMotionEvent == null || lastMotionEvent == null) {
+ return true
+ }
+ return abs(firstMotionEvent!!.x - lastMotionEvent!!.x) >=
+ abs(firstMotionEvent!!.y - lastMotionEvent!!.y)
+ }
+
/** Listener interface to be notified when the user starts or stops scrubbing. */
interface ScrubbingChangeListener {
fun onScrubbingChanged(scrubbing: Boolean)
@@ -367,7 +399,7 @@
}
override fun onStopTrackingTouch(bar: SeekBar) {
- if (falsingManager.isFalseTouch(MEDIA_SEEKBAR)) {
+ if (!viewModel.isValidSeekbarGrab() || falsingManager.isFalseTouch(MEDIA_SEEKBAR)) {
viewModel.onSeekFalse()
}
viewModel.onSeek(bar.progress.toLong())
@@ -415,6 +447,8 @@
return false
}
detector.onTouchEvent(event)
+ // Store the last motion event done on seekbar.
+ viewModel.lastMotionEvent = event.copy()
return !shouldGoToSeekBar
}
@@ -459,6 +493,8 @@
if (shouldGoToSeekBar) {
bar.parent?.requestDisallowInterceptTouchEvent(true)
}
+ // Store the first motion event done on seekbar.
+ viewModel.firstMotionEvent = event.copy()
return shouldGoToSeekBar
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt
index 70f2dee..0b33904 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt
@@ -180,5 +180,7 @@
R.id.media_cover2_container,
R.id.media_cover3_container
)
+
+ val backgroundId = R.id.sizing_view
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
index cd51d92..4bca778 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
@@ -61,37 +61,6 @@
companion object {
@JvmField val GUTS_ANIMATION_DURATION = 500L
- val controlIds =
- setOf(
- R.id.media_progress_bar,
- R.id.actionNext,
- R.id.actionPrev,
- R.id.action0,
- R.id.action1,
- R.id.action2,
- R.id.action3,
- R.id.action4,
- R.id.media_scrubbing_elapsed_time,
- R.id.media_scrubbing_total_time
- )
-
- val detailIds =
- setOf(
- R.id.header_title,
- R.id.header_artist,
- R.id.media_explicit_indicator,
- R.id.actionPlayPause,
- )
-
- val backgroundIds =
- setOf(
- R.id.album_art,
- R.id.turbulence_noise_view,
- R.id.touch_ripple_view,
- )
-
- // Sizing view id for recommendation card view.
- val recSizingViewId = R.id.sizing_view
}
/** A listener when the current dimensions of the player change */
@@ -182,15 +151,14 @@
lastOrientation = newOrientation
// Update the height of media controls for the expanded layout. it is needed
// for large screen devices.
- if (type == TYPE.PLAYER) {
- backgroundIds.forEach { id ->
- expandedLayout.getConstraint(id).layout.mHeight =
- context.resources.getDimensionPixelSize(
- R.dimen.qs_media_session_height_expanded
- )
+ val backgroundIds =
+ if (type == TYPE.PLAYER) {
+ MediaViewHolder.backgroundIds
+ } else {
+ setOf(RecommendationViewHolder.backgroundId)
}
- } else {
- expandedLayout.getConstraint(recSizingViewId).layout.mHeight =
+ backgroundIds.forEach { id ->
+ expandedLayout.getConstraint(id).layout.mHeight =
context.resources.getDimensionPixelSize(
R.dimen.qs_media_session_height_expanded
)
@@ -338,19 +306,19 @@
squishedViewState.height = squishedHeight
// We are not overriding the squishedViewStates height but only the children to avoid
// them remeasuring the whole view. Instead it just remains as the original size
- backgroundIds.forEach { id ->
+ MediaViewHolder.backgroundIds.forEach { id ->
squishedViewState.widgetStates.get(id)?.let { state -> state.height = squishedHeight }
}
// media player
calculateWidgetGroupAlphaForSquishiness(
- controlIds,
+ MediaViewHolder.expandedBottomActionIds,
squishedViewState.measureHeight.toFloat(),
squishedViewState,
squishFraction
)
calculateWidgetGroupAlphaForSquishiness(
- detailIds,
+ MediaViewHolder.detailIds,
squishedViewState.measureHeight.toFloat(),
squishedViewState,
squishFraction
@@ -660,7 +628,7 @@
result.height = result.measureHeight
result.width = result.measureWidth
// Make sure all background views are also resized such that their size is correct
- backgroundIds.forEach { id ->
+ MediaViewHolder.backgroundIds.forEach { id ->
result.widgetStates.get(id)?.let { state ->
state.height = result.height
state.width = result.width
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index e8ef612..b0fb349 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -25,6 +25,7 @@
import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.view.InsetsSource.FLAG_SUPPRESS_SCRIM;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
@@ -740,7 +741,7 @@
mView.setComponents(mRecentsOptional);
if (mCentralSurfacesOptionalLazy.get().isPresent()) {
mView.setComponents(
- mCentralSurfacesOptionalLazy.get().get().getNotificationPanelViewController());
+ mCentralSurfacesOptionalLazy.get().get().getShadeViewController());
}
mView.setDisabledFlags(mDisabledFlags1, mSysUiFlagsContainer);
mView.setOnVerticalChangedListener(this::onVerticalChanged);
@@ -1342,8 +1343,8 @@
private void onVerticalChanged(boolean isVertical) {
Optional<CentralSurfaces> cs = mCentralSurfacesOptionalLazy.get();
- if (cs.isPresent() && cs.get().getNotificationPanelViewController() != null) {
- cs.get().getNotificationPanelViewController().setQsScrimEnabled(!isVertical);
+ if (cs.isPresent() && cs.get().getShadeViewController() != null) {
+ cs.get().getShadeViewController().setQsScrimEnabled(!isVertical);
}
}
@@ -1717,12 +1718,15 @@
if (insetsHeight != -1 && !mEdgeBackGestureHandler.isButtonForcedVisible()) {
navBarProvider.setInsetsSize(Insets.of(0, 0, 0, insetsHeight));
}
+ final boolean needsScrim = userContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_navBarNeedsScrim);
+ navBarProvider.setFlags(needsScrim ? 0 : FLAG_SUPPRESS_SCRIM, FLAG_SUPPRESS_SCRIM);
final InsetsFrameProvider tappableElementProvider = new InsetsFrameProvider(
mInsetsSourceOwner, 0, WindowInsets.Type.tappableElement());
- final boolean navBarTapThrough = userContext.getResources().getBoolean(
+ final boolean tapThrough = userContext.getResources().getBoolean(
com.android.internal.R.bool.config_navBarTapThrough);
- if (navBarTapThrough) {
+ if (tapThrough) {
tappableElementProvider.setInsetsSize(Insets.NONE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 5d598e8..94f01b8 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -74,7 +74,7 @@
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import com.android.systemui.recents.Recents;
import com.android.systemui.settings.DisplayTracker;
-import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shared.rotation.FloatingRotationButton;
import com.android.systemui.shared.rotation.RotationButton.RotationButtonUpdatesCallback;
import com.android.systemui.shared.rotation.RotationButtonController;
@@ -149,7 +149,7 @@
private NavigationBarInflaterView mNavigationInflaterView;
private Optional<Recents> mRecentsOptional = Optional.empty();
@Nullable
- private NotificationPanelViewController mPanelView;
+ private ShadeViewController mPanelView;
private RotationContextButton mRotationContextButton;
private FloatingRotationButton mFloatingRotationButton;
private RotationButtonController mRotationButtonController;
@@ -346,7 +346,8 @@
mRecentsOptional = recentsOptional;
}
- public void setComponents(NotificationPanelViewController panel) {
+ /** */
+ public void setComponents(ShadeViewController panel) {
mPanelView = panel;
updatePanelSystemUiStateFlags();
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 5f4e7cac..aab898e 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -30,6 +30,7 @@
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ShortcutManager
+import android.graphics.drawable.Icon
import android.os.Build
import android.os.UserHandle
import android.os.UserManager
@@ -84,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" }
@@ -172,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" }
@@ -187,9 +188,10 @@
logDebug { "onShowNoteTask - start: $info on user#${user.identifier}" }
when (info.launchMode) {
is NoteTaskLaunchMode.AppBubble -> {
- // TODO: provide app bubble icon
val intent = createNoteTaskIntent(info)
- bubbles.showOrHideAppBubble(intent, user, null /* icon */)
+ val icon =
+ Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
+ bubbles.showOrHideAppBubble(intent, user, icon)
// App bubble logging happens on `onBubbleExpandChanged`.
logDebug { "onShowNoteTask - opened as app bubble: $info" }
}
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/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 0a188e0..a43f520 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -99,7 +99,7 @@
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.QuickStepContract;
@@ -205,7 +205,7 @@
// TODO move this logic to message queue
mCentralSurfacesOptionalLazy.get().ifPresent(centralSurfaces -> {
if (event.getActionMasked() == ACTION_DOWN) {
- centralSurfaces.getNotificationPanelViewController()
+ centralSurfaces.getShadeViewController()
.startExpandLatencyTracking();
}
mHandler.post(() -> {
@@ -676,9 +676,9 @@
mNavBarControllerLazy.get().getDefaultNavigationBar();
final NavigationBarView navBarView =
mNavBarControllerLazy.get().getNavigationBarView(mContext.getDisplayId());
- final NotificationPanelViewController panelController =
+ final ShadeViewController panelController =
mCentralSurfacesOptionalLazy.get()
- .map(CentralSurfaces::getNotificationPanelViewController)
+ .map(CentralSurfaces::getShadeViewController)
.orElse(null);
if (SysUiState.DEBUG) {
Log.d(TAG_OPS, "Updating sysui state flags: navBarFragment=" + navBarFragment
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index a4a7d4c..9e204e4 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -178,7 +178,6 @@
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -243,11 +242,6 @@
public final class NotificationPanelViewController implements ShadeSurface, Dumpable {
public static final String TAG = NotificationPanelView.class.getSimpleName();
- public static final float FLING_MAX_LENGTH_SECONDS = 0.6f;
- public static final float FLING_SPEED_UP_FACTOR = 0.6f;
- public static final float FLING_CLOSING_MAX_LENGTH_SECONDS = 0.6f;
- public static final float FLING_CLOSING_SPEED_UP_FACTOR = 0.6f;
- public static final int WAKEUP_ANIMATION_DELAY_MS = 250;
private static final boolean DEBUG_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
private static final boolean SPEW_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
private static final boolean DEBUG_DRAWABLE = false;
@@ -255,12 +249,6 @@
VibrationEffect.get(VibrationEffect.EFFECT_STRENGTH_MEDIUM, false);
/** The parallax amount of the quick settings translation when dragging down the panel. */
public static final float QS_PARALLAX_AMOUNT = 0.175f;
- /** Fling expanding QS. */
- public static final int FLING_EXPAND = 0;
- /** Fling collapsing QS, potentially stopping when QS becomes QQS. */
- public static final int FLING_COLLAPSE = 1;
- /** Fling until QS is completely hidden. */
- public static final int FLING_HIDE = 2;
/** The delay to reset the hint text when the hint animation is finished running. */
private static final int HINT_RESET_DELAY_MS = 1200;
private static final long ANIMATION_DELAY_ICON_FADE_IN =
@@ -870,8 +858,8 @@
mKeyguardBypassController = bypassController;
mUpdateMonitor = keyguardUpdateMonitor;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
- lockscreenShadeTransitionController.setNotificationPanelController(this);
- shadeTransitionController.setNotificationPanelViewController(this);
+ lockscreenShadeTransitionController.setShadeViewController(this);
+ shadeTransitionController.setShadeViewController(this);
dynamicPrivacyController.addListener(this::onDynamicPrivacyChanged);
quickSettingsController.setExpansionHeightListener(this::onQsSetExpansionHeightCalled);
quickSettingsController.setQsStateUpdateListener(this::onQsStateUpdated);
@@ -1023,7 +1011,7 @@
mKeyguardStatusBarViewController =
mKeyguardStatusBarViewComponentFactory.build(
mKeyguardStatusBar,
- mNotificationPanelViewStateProvider)
+ mShadeViewStateProvider)
.getKeyguardStatusBarViewController();
mKeyguardStatusBarViewController.init();
@@ -1618,10 +1606,7 @@
return isOnAod();
}
- /**
- * Notify us that {@link NotificationWakeUpCoordinator} is going to play the doze wakeup
- * animation after a delay. If so, we'll keep the clock centered until that animation starts.
- */
+ @Override
public void setWillPlayDelayedDozeAmountAnimation(boolean willPlay) {
if (mWillPlayDelayedDozeAmountAnimation == willPlay) return;
@@ -1709,8 +1694,7 @@
final float extraSpaceForShelf = lockIconPadding - noShelfOverlapBottomPadding;
if (extraSpaceForShelf > 0f) {
- return Math.min(mNotificationShelfController.getIntrinsicHeight(),
- extraSpaceForShelf);
+ return Math.min(getShelfHeight(), extraSpaceForShelf);
}
return 0f;
}
@@ -1732,10 +1716,18 @@
mNotificationStackScrollLayoutController.getView(),
getVerticalSpaceForLockscreenNotifications(),
getVerticalSpaceForLockscreenShelf(),
- mNotificationShelfController.getIntrinsicHeight()
+ getShelfHeight()
);
}
+ private int getShelfHeight() {
+ if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
+ return mNotificationStackScrollLayoutController.getShelfHeight();
+ } else {
+ return mNotificationShelfController.getIntrinsicHeight();
+ }
+ }
+
private void updateClock() {
if (mIsOcclusionTransitionRunning) {
return;
@@ -3308,16 +3300,6 @@
public boolean hasPulsingNotifications() {
return mNotificationListContainer.hasPulsingNotifications();
}
-
- @Override
- public ActivatableNotificationView getActivatedChild() {
- return mNotificationStackScrollLayoutController.getActivatedChild();
- }
-
- @Override
- public void setActivatedChild(ActivatableNotificationView o) {
- mNotificationStackScrollLayoutController.setActivatedChild(o);
- }
}
@Override
@@ -3338,12 +3320,12 @@
mGestureRecorder = recorder;
mHideExpandedRunnable = hideExpandedRunnable;
+ mNotificationShelfController = notificationShelfController;
if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
mNotificationStackScrollLayoutController.setShelfController(
notificationShelfController);
+ mLockscreenShadeTransitionController.bindController(notificationShelfController);
}
- mNotificationShelfController = notificationShelfController;
- mLockscreenShadeTransitionController.bindController(notificationShelfController);
updateMaxDisplayedNotifications(true);
}
@@ -4384,29 +4366,8 @@
}
}
- /**
- * An interface that provides the current state of the notification panel and related views,
- * which is needed to calculate {@link KeyguardStatusBarView}'s state in
- * {@link KeyguardStatusBarViewController}.
- */
- public interface NotificationPanelViewStateProvider {
- /** Returns the expanded height of the panel view. */
- float getPanelViewExpandedHeight();
-
- /**
- * Returns true if heads up should be visible.
- *
- * TODO(b/138786270): If HeadsUpAppearanceController was injectable, we could inject it into
- * {@link KeyguardStatusBarViewController} and remove this method.
- */
- boolean shouldHeadsUpBeVisible();
-
- /** Return the fraction of the shade that's expanded, when in lockscreen. */
- float getLockscreenShadeDragProgress();
- }
-
- private final NotificationPanelViewStateProvider mNotificationPanelViewStateProvider =
- new NotificationPanelViewStateProvider() {
+ private final ShadeViewStateProvider mShadeViewStateProvider =
+ new ShadeViewStateProvider() {
@Override
public float getPanelViewExpandedHeight() {
return getExpandedHeight();
@@ -4423,13 +4384,7 @@
}
};
- /**
- * Reconfigures the shade to show the AOD UI (clock, smartspace, etc). This is called by the
- * screen off animation controller in order to animate in AOD without "actually" fully switching
- * to the KEYGUARD state, which is a heavy transition that causes jank as 10+ files react to the
- * change.
- */
- @VisibleForTesting
+ @Override
public void showAodUi() {
setDozing(true /* dozing */, false /* animate */);
mStatusBarStateController.setUpcomingState(KEYGUARD);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 2f4cc14..ebbf1b5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -288,7 +288,6 @@
mService.userActivity();
mService.wakeUpIfDozing(
mClock.uptimeMillis(),
- mView,
"LOCK_ICON_TOUCH",
PowerManager.WAKE_REASON_GESTURE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
index b42bdaa..fd82e2f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
@@ -90,7 +90,6 @@
shadeLogger.d("Single tap handled, requesting centralSurfaces.wakeUpIfDozing")
centralSurfaces.wakeUpIfDozing(
SystemClock.uptimeMillis(),
- notificationShadeWindowView,
"PULSING_SINGLE_TAP",
PowerManager.WAKE_REASON_TAP
)
@@ -116,7 +115,6 @@
) {
centralSurfaces.wakeUpIfDozing(
SystemClock.uptimeMillis(),
- notificationShadeWindowView,
"PULSING_DOUBLE_TAP",
PowerManager.WAKE_REASON_TAP
)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
index a931838..1839e13 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
@@ -20,9 +20,9 @@
import com.android.systemui.log.dagger.ShadeLog
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel
-import com.android.systemui.shade.NotificationPanelViewController.FLING_COLLAPSE
-import com.android.systemui.shade.NotificationPanelViewController.FLING_EXPAND
-import com.android.systemui.shade.NotificationPanelViewController.FLING_HIDE
+import com.android.systemui.shade.ShadeViewController.Companion.FLING_COLLAPSE
+import com.android.systemui.shade.ShadeViewController.Companion.FLING_EXPAND
+import com.android.systemui.shade.ShadeViewController.Companion.FLING_HIDE
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
index b698bd3..5ac36bf 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
@@ -94,6 +94,12 @@
fun setTouchAndAnimationDisabled(disabled: Boolean)
/**
+ * Notify us that {@link NotificationWakeUpCoordinator} is going to play the doze wakeup
+ * animation after a delay. If so, we'll keep the clock centered until that animation starts.
+ */
+ fun setWillPlayDelayedDozeAmountAnimation(willPlay: Boolean)
+
+ /**
* Sets the dozing state.
*
* @param dozing `true` when dozing.
@@ -104,18 +110,12 @@
/** @see view.setImportantForAccessibility */
fun setImportantForAccessibility(mode: Int)
- /** Sets Qs ScrimEnabled and updates QS state. */
- fun setQsScrimEnabled(qsScrimEnabled: Boolean)
-
/** Sets the view's X translation to zero. */
fun resetTranslation()
/** Sets the view's alpha to max. */
fun resetAlpha()
- /** @see ViewGroupFadeHelper.reset */
- fun resetViewGroupFade()
-
/** Called when Back gesture has been committed (i.e. a back event has definitely occurred) */
fun onBackPressed()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 34c9f6d..d5a9e95 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -18,11 +18,12 @@
import android.view.MotionEvent
import android.view.ViewGroup
import com.android.systemui.statusbar.RemoteInputController
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView
+import com.android.systemui.statusbar.phone.KeyguardStatusBarView
+import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController
import java.util.function.Consumer
/**
@@ -148,6 +149,9 @@
/** Sets whether the screen has temporarily woken up to display notifications. */
fun setPulsing(pulsing: Boolean)
+ /** Sets Qs ScrimEnabled and updates QS state. */
+ fun setQsScrimEnabled(qsScrimEnabled: Boolean)
+
/** Sets the top spacing for the ambient indicator. */
fun setAmbientIndicationTop(ambientIndicationTop: Int, ambientTextVisible: Boolean)
@@ -167,6 +171,9 @@
*/
val isUnlockHintRunning: Boolean
+ /** @see ViewGroupFadeHelper.reset */
+ fun resetViewGroupFade()
+
/**
* Set the alpha and translationY of the keyguard elements which only show on the lockscreen,
* but not in shade locked / shade. This is used when dragging down to the full shade.
@@ -184,6 +191,14 @@
fun setKeyguardStatusBarAlpha(alpha: Float)
/**
+ * Reconfigures the shade to show the AOD UI (clock, smartspace, etc). This is called by the
+ * screen off animation controller in order to animate in AOD without "actually" fully switching
+ * to the KEYGUARD state, which is a heavy transition that causes jank as 10+ files react to the
+ * change.
+ */
+ fun showAodUi()
+
+ /**
* This method should not be used anymore, you should probably use [.isShadeFullyOpen] instead.
* It was overused as indicating if shade is open or we're on keyguard/AOD. Moving forward we
* should be explicit about the what state we're checking.
@@ -209,6 +224,23 @@
/** Returns the ShadeNotificationPresenter. */
val shadeNotificationPresenter: ShadeNotificationPresenter
+
+ companion object {
+ const val WAKEUP_ANIMATION_DELAY_MS = 250
+ const val FLING_MAX_LENGTH_SECONDS = 0.6f
+ const val FLING_SPEED_UP_FACTOR = 0.6f
+ const val FLING_CLOSING_MAX_LENGTH_SECONDS = 0.6f
+ const val FLING_CLOSING_SPEED_UP_FACTOR = 0.6f
+
+ /** Fling expanding QS. */
+ const val FLING_EXPAND = 0
+
+ /** Fling collapsing QS, potentially stopping when QS becomes QQS. */
+ const val FLING_COLLAPSE = 1
+
+ /** Fling until QS is completely hidden. */
+ const val FLING_HIDE = 2
+ }
}
/** Manages listeners for when users begin expanding the shade from a HUN. */
@@ -254,7 +286,24 @@
/** Returns whether the screen has temporarily woken up to display notifications. */
fun hasPulsingNotifications(): Boolean
+}
- /** The current activated notification. */
- var activatedChild: ActivatableNotificationView?
+/**
+ * An interface that provides the current state of the notification panel and related views, which
+ * is needed to calculate [KeyguardStatusBarView]'s state in [KeyguardStatusBarViewController].
+ */
+interface ShadeViewStateProvider {
+ /** Returns the expanded height of the panel view. */
+ val panelViewExpandedHeight: Float
+
+ /**
+ * Returns true if heads up should be visible.
+ *
+ * TODO(b/138786270): If HeadsUpAppearanceController was injectable, we could inject it into
+ * [KeyguardStatusBarViewController] and remove this method.
+ */
+ fun shouldHeadsUpBeVisible(): Boolean
+
+ /** Return the fraction of the shade that's expanded, when in lockscreen. */
+ val lockscreenShadeDragProgress: Float
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
index 129d09e..41be526 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
@@ -22,10 +22,10 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.qs.QS
-import com.android.systemui.shade.NotificationPanelViewController
import com.android.systemui.shade.PanelState
import com.android.systemui.shade.ShadeExpansionChangeEvent
import com.android.systemui.shade.ShadeExpansionStateManager
+import com.android.systemui.shade.ShadeViewController
import com.android.systemui.shade.panelStateToString
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -47,7 +47,7 @@
private val statusBarStateController: SysuiStatusBarStateController,
) {
- lateinit var notificationPanelViewController: NotificationPanelViewController
+ lateinit var shadeViewController: ShadeViewController
lateinit var notificationStackScrollLayoutController: NotificationStackScrollLayoutController
lateinit var qs: QS
@@ -93,7 +93,7 @@
currentPanelState: ${currentPanelState?.panelStateToString()}
lastPanelExpansionChangeEvent: $lastShadeExpansionChangeEvent
qs.isInitialized: ${this::qs.isInitialized}
- npvc.isInitialized: ${this::notificationPanelViewController.isInitialized}
+ npvc.isInitialized: ${this::shadeViewController.isInitialized}
nssl.isInitialized: ${this::notificationStackScrollLayoutController.isInitialized}
""".trimIndent())
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
index f7d37e6..4ef2063 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
@@ -20,7 +20,6 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope;
import com.android.systemui.statusbar.notification.stack.AmbientState;
@@ -107,11 +106,6 @@
}
@Override
- public void setOnActivatedListener(ActivatableNotificationView.OnActivatedListener listener) {
- mView.setOnActivatedListener(listener);
- }
-
- @Override
public void setOnClickListener(View.OnClickListener onClickListener) {
mView.setOnClickListener(onClickListener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionController.kt
index 5fb5002..fec6112 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionController.kt
@@ -6,7 +6,7 @@
import com.android.systemui.R
import com.android.systemui.dump.DumpManager
import com.android.systemui.media.controls.ui.MediaHierarchyManager
-import com.android.systemui.shade.NotificationPanelViewController
+import com.android.systemui.shade.ShadeViewController
import com.android.systemui.statusbar.policy.ConfigurationController
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@@ -17,7 +17,7 @@
@AssistedInject
constructor(
private val mediaHierarchyManager: MediaHierarchyManager,
- @Assisted private val notificationPanelController: NotificationPanelViewController,
+ @Assisted private val notificationPanelController: ShadeViewController,
context: Context,
configurationController: ConfigurationController,
dumpManager: DumpManager
@@ -114,7 +114,7 @@
@AssistedFactory
fun interface Factory {
fun create(
- notificationPanelController: NotificationPanelViewController
+ notificationPanelController: ShadeViewController
): LockscreenShadeKeyguardTransitionController
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 63e29d1..faf592e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -30,7 +30,7 @@
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.qs.QS
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.shade.NotificationPanelViewController
+import com.android.systemui.shade.ShadeViewController
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
@@ -79,7 +79,7 @@
private set
private var useSplitShade: Boolean = false
private lateinit var nsslController: NotificationStackScrollLayoutController
- lateinit var notificationPanelController: NotificationPanelViewController
+ lateinit var shadeViewController: ShadeViewController
lateinit var centralSurfaces: CentralSurfaces
lateinit var qS: QS
@@ -182,7 +182,7 @@
}
private val keyguardTransitionController by lazy {
- keyguardTransitionControllerFactory.create(notificationPanelController)
+ keyguardTransitionControllerFactory.create(shadeViewController)
}
private val qsTransitionController = qsTransitionControllerFactory.create { qS }
@@ -276,7 +276,6 @@
if (statusBarStateController.state == StatusBarState.KEYGUARD) {
centralSurfaces.wakeUpIfDozing(
SystemClock.uptimeMillis(),
- it,
"SHADE_CLICK",
PowerManager.WAKE_REASON_GESTURE,
)
@@ -320,7 +319,7 @@
startingChild.onExpandedByGesture(
true /* drag down is always an open */)
}
- notificationPanelController.transitionToExpandedShade(delay)
+ shadeViewController.transitionToExpandedShade(delay)
callbacks.forEach { it.setTransitionToFullShadeAmount(0f,
true /* animated */, delay) }
@@ -531,7 +530,7 @@
} else {
// Let's only animate notifications
animationHandler = { delay: Long ->
- notificationPanelController.transitionToExpandedShade(delay)
+ shadeViewController.transitionToExpandedShade(delay)
}
}
goToLockedShadeInternal(expandedView, animationHandler,
@@ -649,7 +648,7 @@
*/
private fun performDefaultGoToFullShadeAnimation(delay: Long) {
logger.logDefaultGoToFullShadeAnimation(delay)
- notificationPanelController.transitionToExpandedShade(delay)
+ shadeViewController.transitionToExpandedShade(delay)
animateAppear(delay)
}
@@ -674,7 +673,7 @@
} else {
pulseHeight = height
val overflow = nsslController.setPulseHeight(height)
- notificationPanelController.setOverStretchAmount(overflow)
+ shadeViewController.setOverStretchAmount(overflow)
val transitionHeight = if (keyguardBypassController.bypassEnabled) height else 0.0f
transitionToShadeAmountCommon(transitionHeight)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index ea9817c..1714f48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -24,6 +24,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
+import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
@@ -43,6 +44,7 @@
import android.view.View;
import android.widget.ImageView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dumpable;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -69,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;
@@ -78,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.
@@ -117,6 +119,8 @@
private ScrimController mScrimController;
@Nullable
private LockscreenWallpaper mLockscreenWallpaper;
+ @VisibleForTesting
+ boolean mIsLockscreenLiveWallpaperEnabled;
private final DelayableExecutor mMainExecutor;
@@ -157,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(
@@ -179,7 +220,8 @@
StatusBarStateController statusBarStateController,
SysuiColorExtractor colorExtractor,
KeyguardStateController keyguardStateController,
- DumpManager dumpManager) {
+ DumpManager dumpManager,
+ WallpaperManager wallpaperManager) {
mContext = context;
mMediaArtworkProcessor = mediaArtworkProcessor;
mKeyguardBypassController = keyguardBypassController;
@@ -195,6 +237,7 @@
mStatusBarStateController = statusBarStateController;
mColorExtractor = colorExtractor;
mKeyguardStateController = keyguardStateController;
+ mIsLockscreenLiveWallpaperEnabled = wallpaperManager.isLockscreenLiveWallpaperEnabled();
setupNotifPipeline();
@@ -307,6 +350,7 @@
return mMediaNotificationKey;
}
+ @VisibleForTesting
public MediaMetadata getMediaMetadata() {
return mMediaMetadata;
}
@@ -344,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.
@@ -377,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);
@@ -474,13 +518,16 @@
* Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
*/
public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
+
+ if (mIsLockscreenLiveWallpaperEnabled) return;
+
Trace.beginSection("CentralSurfaces#updateMediaMetaData");
if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) {
Trace.endSection();
return;
}
- if (mBackdrop == null) {
+ if (getBackDropView() == null) {
Trace.endSection();
return; // called too early
}
@@ -709,6 +756,12 @@
&& (mBackdropFront.isVisibleToUser() || mBackdropBack.isVisibleToUser());
}
+ // TODO(b/273443374) temporary test helper; remove
+ @VisibleForTesting
+ BackDropView getBackDropView() {
+ return mBackdrop;
+ }
+
/**
* {@link AsyncTask} to prepare album art for use as backdrop on lock screen.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index cb414ba..1c9bc60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -15,7 +15,6 @@
*/
package com.android.systemui.statusbar;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
/**
@@ -25,8 +24,7 @@
* for affecting the state of the system (e.g. starting an intent, given that the presenter may
* want to perform some action before doing so).
*/
-public interface NotificationPresenter extends ExpandableNotificationRow.OnExpandClickListener,
- ActivatableNotificationView.OnActivatedListener {
+public interface NotificationPresenter extends ExpandableNotificationRow.OnExpandClickListener {
/**
* Returns true if the presenter is not visible. For example, it may not be necessary to do
* animations if this returns true.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 9e2a07e..c519115 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -124,7 +124,7 @@
View view, PendingIntent pendingIntent, RemoteViews.RemoteResponse response) {
mCentralSurfacesOptionalLazy.get().ifPresent(
centralSurfaces -> centralSurfaces.wakeUpIfDozing(
- SystemClock.uptimeMillis(), view, "NOTIFICATION_CLICK",
+ SystemClock.uptimeMillis(), "NOTIFICATION_CLICK",
PowerManager.WAKE_REASON_GESTURE));
final NotificationEntry entry = getNotificationForParent(view.getParent());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt
index 07cfd0d..1619dda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.kt
@@ -21,8 +21,6 @@
import android.view.View.OnClickListener
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView.OnActivatedListener
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
@@ -43,9 +41,6 @@
/** Whether or not the shelf can modify the color of notifications in the shade. */
fun canModifyColorOfNotifications(): Boolean
- /** @see ActivatableNotificationView.setOnActivatedListener */
- fun setOnActivatedListener(listener: OnActivatedListener)
-
/** Binds the shelf to the host [NotificationStackScrollLayout], via its Controller. */
fun bind(
ambientState: AmbientState,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index 34300c7..f6c9a5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.dagger;
import android.app.IActivityManager;
+import android.app.WallpaperManager;
import android.content.Context;
import android.os.RemoteException;
import android.service.dreams.IDreamManager;
@@ -142,7 +143,8 @@
StatusBarStateController statusBarStateController,
SysuiColorExtractor colorExtractor,
KeyguardStateController keyguardStateController,
- DumpManager dumpManager) {
+ DumpManager dumpManager,
+ WallpaperManager wallpaperManager) {
return new NotificationMediaManager(
context,
centralSurfacesOptionalLazy,
@@ -157,7 +159,8 @@
statusBarStateController,
colorExtractor,
keyguardStateController,
- dumpManager);
+ dumpManager,
+ wallpaperManager);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
index 00d8c42..5f28ecb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
@@ -31,26 +31,12 @@
fun isDevLoggingEnabled(): Boolean =
featureFlags.isEnabled(Flags.NOTIFICATION_PIPELINE_DEVELOPER_LOGGING)
- fun fullScreenIntentRequiresKeyguard(): Boolean =
- featureFlags.isEnabled(Flags.FSI_REQUIRES_KEYGUARD)
-
- fun fsiOnDNDUpdate(): Boolean = featureFlags.isEnabled(Flags.FSI_ON_DND_UPDATE)
-
- fun forceDemoteFsi(): Boolean =
- sysPropFlags.isEnabled(NotificationFlags.FSI_FORCE_DEMOTE)
-
- fun showStickyHunForDeniedFsi(): Boolean =
- sysPropFlags.isEnabled(NotificationFlags.SHOW_STICKY_HUN_FOR_DENIED_FSI)
-
fun allowDismissOngoing(): Boolean =
sysPropFlags.isEnabled(NotificationFlags.ALLOW_DISMISS_ONGOING)
fun isOtpRedactionEnabled(): Boolean =
sysPropFlags.isEnabled(NotificationFlags.OTP_REDACTION)
- val shouldFilterUnseenNotifsOnKeyguard: Boolean
- get() = featureFlags.isEnabled(Flags.FILTER_UNSEEN_NOTIFS_ON_KEYGUARD)
-
val isNoHunForOldWhenEnabled: Boolean
get() = featureFlags.isEnabled(Flags.NO_HUN_FOR_OLD_WHEN)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
index 705cf92..bab553e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
@@ -71,7 +71,7 @@
}
mCentralSurfacesOptional.ifPresent(centralSurfaces -> centralSurfaces.wakeUpIfDozing(
- SystemClock.uptimeMillis(), v, "NOTIFICATION_CLICK",
+ SystemClock.uptimeMillis(), "NOTIFICATION_CLICK",
PowerManager.WAKE_REASON_GESTURE));
final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 20af6ca..fe0b28d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -26,9 +26,9 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.shade.NotificationPanelViewController.WAKEUP_ANIMATION_DELAY_MS
import com.android.systemui.shade.ShadeExpansionChangeEvent
import com.android.systemui.shade.ShadeExpansionListener
+import com.android.systemui.shade.ShadeViewController
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
@@ -383,7 +383,7 @@
ObjectAnimator.ofFloat(this, delayedDozeAmount, 0.0f).apply {
interpolator = InterpolatorsAndroidX.LINEAR
duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong()
- startDelay = WAKEUP_ANIMATION_DELAY_MS.toLong()
+ startDelay = ShadeViewController.WAKEUP_ANIMATION_DELAY_MS.toLong()
doOnStart {
wakeUpListeners.forEach { it.onDelayedDozeAmountAnimationRunning(true) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
index 4d0e746..0529c94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
@@ -392,8 +392,7 @@
mNotificationInterruptStateProvider.logFullScreenIntentDecision(entry, fsiDecision)
if (fsiDecision.shouldLaunch) {
mLaunchFullScreenIntentProvider.launchFullScreenIntent(entry)
- } else if (mFlags.fsiOnDNDUpdate() &&
- fsiDecision == FullScreenIntentDecision.NO_FSI_SUPPRESSED_ONLY_BY_DND) {
+ } else if (fsiDecision == FullScreenIntentDecision.NO_FSI_SUPPRESSED_ONLY_BY_DND) {
// If DND was the only reason this entry was suppressed, note it for potential
// reconsideration on later ranking updates.
addForFSIReconsideration(entry, mSystemClock.currentTimeMillis())
@@ -509,7 +508,7 @@
// - was suppressed from FSI launch only by a DND suppression
// - is within the recency window for reconsideration
// If any of these entries are no longer suppressed, launch the FSI now.
- if (mFlags.fsiOnDNDUpdate() && isCandidateForFSIReconsideration(entry)) {
+ if (isCandidateForFSIReconsideration(entry)) {
val decision =
mNotificationInterruptStateProvider.getFullScreenIntentDecision(entry)
if (decision.shouldLaunch) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 6322edf..4cbbefe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -95,9 +95,7 @@
pipeline.addFinalizeFilter(notifFilter)
keyguardNotificationVisibilityProvider.addOnStateChangedListener(::invalidateListFromFilter)
updateSectionHeadersVisibility()
- if (notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard) {
- attachUnseenFilter(pipeline)
- }
+ attachUnseenFilter(pipeline)
}
private fun attachUnseenFilter(pipeline: NotifPipeline) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 611edf8..38bbb35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification.collection.inflation;
-import static com.android.systemui.flags.Flags.NOTIFICATION_INLINE_REPLY_ANIMATION;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
@@ -31,7 +30,6 @@
import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -73,7 +71,6 @@
private NotificationListContainer mListContainer;
private BindRowCallback mBindRowCallback;
private NotificationClicker mNotificationClicker;
- private FeatureFlags mFeatureFlags;
@Inject
public NotificationRowBinderImpl(
@@ -85,8 +82,7 @@
RowContentBindStage rowContentBindStage,
Provider<RowInflaterTask> rowInflaterTaskProvider,
ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder,
- IconManager iconManager,
- FeatureFlags featureFlags) {
+ IconManager iconManager) {
mContext = context;
mNotifBindPipeline = notifBindPipeline;
mRowContentBindStage = rowContentBindStage;
@@ -96,7 +92,6 @@
mRowInflaterTaskProvider = rowInflaterTaskProvider;
mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder;
mIconManager = iconManager;
- mFeatureFlags = featureFlags;
}
/**
@@ -177,12 +172,9 @@
private void bindRow(NotificationEntry entry, ExpandableNotificationRow row) {
mListContainer.bindRow(row);
mNotificationRemoteInputManager.bindRow(row);
- row.setOnActivatedListener(mPresenter);
entry.setRow(row);
mNotifBindPipeline.manageRow(entry, row);
mBindRowCallback.onBindRow(row);
- row.setInlineReplyAnimationFlagEnabled(
- mFeatureFlags.isEnabled(NOTIFICATION_INLINE_REPLY_ANIMATION));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
index 9a1747a..88994b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
@@ -98,10 +98,6 @@
*/
NO_FSI_NO_HUN_OR_KEYGUARD(false),
/**
- * No conditions blocking FSI launch.
- */
- FSI_EXPECTED_NOT_TO_HUN(true),
- /**
* The notification is coming from a suspended packages, so FSI is suppressed.
*/
NO_FSI_SUSPENDED(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index a48870b..609f9d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -321,30 +321,22 @@
suppressedByDND);
}
- // Check whether FSI requires the keyguard to be showing.
- if (mFlags.fullScreenIntentRequiresKeyguard()) {
-
- // If notification won't HUN and keyguard is showing, launch the FSI.
- if (mKeyguardStateController.isShowing()) {
- if (mKeyguardStateController.isOccluded()) {
- return getDecisionGivenSuppression(
- FullScreenIntentDecision.FSI_KEYGUARD_OCCLUDED,
- suppressedByDND);
- } else {
- // Likely LOCKED_SHADE, but launch FSI anyway
- return getDecisionGivenSuppression(FullScreenIntentDecision.FSI_LOCKED_SHADE,
- suppressedByDND);
- }
+ // If notification won't HUN and keyguard is showing, launch the FSI.
+ if (mKeyguardStateController.isShowing()) {
+ if (mKeyguardStateController.isOccluded()) {
+ return getDecisionGivenSuppression(
+ FullScreenIntentDecision.FSI_KEYGUARD_OCCLUDED,
+ suppressedByDND);
+ } else {
+ // Likely LOCKED_SHADE, but launch FSI anyway
+ return getDecisionGivenSuppression(FullScreenIntentDecision.FSI_LOCKED_SHADE,
+ suppressedByDND);
}
-
- // Detect the case determined by b/231322873 to launch FSI while device is in use,
- // as blocked by the correct implementation, and report the event.
- return getDecisionGivenSuppression(FullScreenIntentDecision.NO_FSI_NO_HUN_OR_KEYGUARD,
- suppressedByDND);
}
- // If the notification won't HUN for some other reason (DND/snooze/etc), launch FSI.
- return getDecisionGivenSuppression(FullScreenIntentDecision.FSI_EXPECTED_NOT_TO_HUN,
+ // Detect the case determined by b/231322873 to launch FSI while device is in use,
+ // as blocked by the correct implementation, and report the event.
+ return getDecisionGivenSuppression(FullScreenIntentDecision.NO_FSI_NO_HUN_OR_KEYGUARD,
suppressedByDND);
}
@@ -409,14 +401,11 @@
}
final boolean isSnoozedPackage = isSnoozedPackage(sbn);
- final boolean fsiRequiresKeyguard = mFlags.fullScreenIntentRequiresKeyguard();
final boolean hasFsi = sbn.getNotification().fullScreenIntent != null;
// Assume any notification with an FSI is time-sensitive (like an alarm or incoming call)
// and ignore whether HUNs have been snoozed for the package.
- final boolean shouldBypassSnooze = fsiRequiresKeyguard && hasFsi;
-
- if (isSnoozedPackage && !shouldBypassSnooze) {
+ if (isSnoozedPackage && !hasFsi) {
if (log) mLogger.logNoHeadsUpPackageSnoozed(entry);
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 68ad49be..766ad88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -28,7 +28,6 @@
import android.view.Choreographer;
import android.view.MotionEvent;
import android.view.View;
-import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
@@ -57,30 +56,6 @@
public abstract class ActivatableNotificationView extends ExpandableOutlineView {
/**
- * The amount of width, which is kept in the end when performing a disappear animation (also
- * the amount from which the horizontal appearing begins)
- */
- private static final float HORIZONTAL_COLLAPSED_REST_PARTIAL = 0.05f;
-
- /**
- * At which point from [0,1] does the horizontal collapse animation end (or start when
- * expanding)? 1.0 meaning that it ends immediately and 0.0 that it is continuously animated.
- */
- private static final float HORIZONTAL_ANIMATION_END = 0.2f;
-
- /**
- * At which point from [0,1] does the horizontal collapse animation start (or start when
- * expanding)? 1.0 meaning that it starts immediately and 0.0 that it is animated at all.
- */
- private static final float HORIZONTAL_ANIMATION_START = 1.0f;
-
- /**
- * At which point from [0,1] does the vertical collapse animation start (or end when
- * expanding) 1.0 meaning that it starts immediately and 0.0 that it is animated at all.
- */
- private static final float VERTICAL_ANIMATION_START = 1.0f;
-
- /**
* A sentinel value when no color should be used. Can be used with {@link #setTintColor(int)}
* or {@link #setOverrideTintColor(int, float)}.
*/
@@ -95,10 +70,6 @@
* The start of the animation is at #ALPHA_APPEAR_START_FRACTION
*/
private static final float ALPHA_APPEAR_END_FRACTION = 1;
- private static final Interpolator ACTIVATE_INVERSE_INTERPOLATOR
- = new PathInterpolator(0.6f, 0, 0.5f, 1);
- private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
- = new PathInterpolator(0, 0, 0.5f, 1);
private final Set<SourceType> mOnDetachResetRoundness = new HashSet<>();
private int mTintedRippleColor;
private int mNormalRippleColor;
@@ -112,10 +83,7 @@
*/
private boolean mActivated;
- private OnActivatedListener mOnActivatedListener;
-
private final Interpolator mSlowOutFastInInterpolator;
- private final Interpolator mSlowOutLinearInInterpolator;
private Interpolator mCurrentAppearInterpolator;
NotificationBackgroundView mBackgroundNormal;
@@ -142,13 +110,11 @@
protected Point mTargetPoint;
private boolean mDismissed;
private boolean mRefocusOnDismiss;
- private AccessibilityManager mAccessibilityManager;
protected boolean mUseRoundnessSourceTypes;
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f);
- mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f);
setClipChildren(false);
setClipToPadding(false);
updateColors();
@@ -230,7 +196,7 @@
public void onTap() {}
/** Sets the last action up time this view was touched. */
- void setLastActionUpTime(long eventTime) {
+ public void setLastActionUpTime(long eventTime) {
mLastActionUpTime = eventTime;
}
@@ -249,10 +215,6 @@
return false;
}
- protected boolean handleSlideBack() {
- return false;
- }
-
/**
* @return whether this view is interactive and can be double tapped
*/
@@ -270,40 +232,12 @@
mBackgroundNormal.setPressedAllowed(allowed);
}
- void makeActive() {
- mActivated = true;
- if (mOnActivatedListener != null) {
- mOnActivatedListener.onActivated(this);
- }
- }
-
- public boolean isActive() {
- return mActivated;
- }
-
- /**
- * Cancels the hotspot and makes the notification inactive.
- */
- public void makeInactive(boolean animate) {
- if (mActivated) {
- mActivated = false;
- }
- if (mOnActivatedListener != null) {
- mOnActivatedListener.onActivationReset(this);
- }
- }
-
private void updateOutlineAlpha() {
float alpha = NotificationStackScrollLayout.BACKGROUND_ALPHA_DIMMED;
alpha = (alpha + (1.0f - alpha) * mNormalBackgroundVisibilityAmount);
setOutlineAlpha(alpha);
}
- private void setNormalBackgroundVisibilityAmount(float normalBackgroundVisibilityAmount) {
- mNormalBackgroundVisibilityAmount = normalBackgroundVisibilityAmount;
- updateOutlineAlpha();
- }
-
@Override
public void setBelowSpeedBump(boolean below) {
super.setBelowSpeedBump(below);
@@ -318,13 +252,6 @@
}
/**
- * @return whether we are below the speed bump
- */
- public boolean isBelowSpeedBump() {
- return mIsBelowSpeedBump;
- }
-
- /**
* Sets the tint color of the background
*/
protected void setTintColor(int color) {
@@ -728,10 +655,6 @@
}
}
- public void setOnActivatedListener(OnActivatedListener onActivatedListener) {
- mOnActivatedListener = onActivatedListener;
- }
-
@Override
public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
int outlineTranslation) {
@@ -782,14 +705,10 @@
return mRefocusOnDismiss || isAccessibilityFocused();
}
- void setTouchHandler(Gefingerpoken touchHandler) {
+ public void setTouchHandler(Gefingerpoken touchHandler) {
mTouchHandler = touchHandler;
}
- public void setAccessibilityManager(AccessibilityManager accessibilityManager) {
- mAccessibilityManager = accessibilityManager;
- }
-
/**
* Enable the support for rounded corner based on the SourceType
* @param enabled true if is supported
@@ -832,9 +751,4 @@
});
}
}
-
- public interface OnActivatedListener {
- void onActivated(ActivatableNotificationView view);
- void onActivationReset(ActivatableNotificationView view);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
index b084a76..028cd18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java
@@ -16,15 +16,12 @@
package com.android.systemui.statusbar.notification.row;
-import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
import com.android.systemui.Gefingerpoken;
-import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.statusbar.phone.NotificationTapHelper;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
@@ -37,44 +34,16 @@
private final ExpandableOutlineViewController mExpandableOutlineViewController;
private final AccessibilityManager mAccessibilityManager;
private final FalsingManager mFalsingManager;
- private final FalsingCollector mFalsingCollector;
- private final NotificationTapHelper mNotificationTapHelper;
private final TouchHandler mTouchHandler = new TouchHandler();
- private boolean mNeedsDimming;
-
@Inject
public ActivatableNotificationViewController(ActivatableNotificationView view,
- NotificationTapHelper.Factory notificationTapHelpFactory,
ExpandableOutlineViewController expandableOutlineViewController,
- AccessibilityManager accessibilityManager, FalsingManager falsingManager,
- FalsingCollector falsingCollector) {
+ AccessibilityManager accessibilityManager, FalsingManager falsingManager) {
super(view);
mExpandableOutlineViewController = expandableOutlineViewController;
mAccessibilityManager = accessibilityManager;
mFalsingManager = falsingManager;
- mFalsingCollector = falsingCollector;
-
- mNotificationTapHelper = notificationTapHelpFactory.create(
- (active) -> {
- if (active) {
- mView.makeActive();
- mFalsingCollector.onNotificationActive();
- } else {
- mView.makeInactive(true /* animate */);
- }
- }, mView::performClick, mView::handleSlideBack);
-
- mView.setOnActivatedListener(new ActivatableNotificationView.OnActivatedListener() {
- @Override
- public void onActivated(ActivatableNotificationView view) {
- mFalsingCollector.onNotificationActive();
- }
-
- @Override
- public void onActivationReset(ActivatableNotificationView view) {
- }
- });
}
/**
@@ -85,7 +54,6 @@
mExpandableOutlineViewController.init();
mView.setOnTouchListener(mTouchHandler);
mView.setTouchHandler(mTouchHandler);
- mView.setAccessibilityManager(mAccessibilityManager);
}
@Override
@@ -99,15 +67,9 @@
}
class TouchHandler implements Gefingerpoken, View.OnTouchListener {
- private boolean mBlockNextTouch;
-
@Override
public boolean onTouch(View v, MotionEvent ev) {
boolean result = false;
- if (mBlockNextTouch) {
- mBlockNextTouch = false;
- return true;
- }
if (ev.getAction() == MotionEvent.ACTION_UP) {
mView.setLastActionUpTime(ev.getEventTime());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 950ab5d..10cdae3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -272,7 +272,6 @@
private OnExpandClickListener mOnExpandClickListener;
private View.OnClickListener mOnFeedbackClickListener;
private Path mExpandingClipPath;
- private boolean mIsInlineReplyAnimationFlagEnabled = false;
// Listener will be called when receiving a long click event.
// Use #setLongPressPosition to optionally assign positional data with the long press.
@@ -969,15 +968,6 @@
}
@Override
- protected boolean handleSlideBack() {
- if (mMenuRow != null && mMenuRow.isMenuVisible()) {
- animateResetTranslation();
- return true;
- }
- return false;
- }
-
- @Override
public boolean isSummaryWithChildren() {
return mIsSummaryWithChildren;
}
@@ -3095,10 +3085,6 @@
return showingLayout != null && showingLayout.requireRowToHaveOverlappingRendering();
}
- public void setInlineReplyAnimationFlagEnabled(boolean isEnabled) {
- mIsInlineReplyAnimationFlagEnabled = isEnabled;
- }
-
@Override
public void setActualHeight(int height, boolean notifyListeners) {
boolean changed = height != getActualHeight();
@@ -3118,11 +3104,7 @@
}
int contentHeight = Math.max(getMinHeight(), height);
for (NotificationContentView l : mLayouts) {
- if (mIsInlineReplyAnimationFlagEnabled) {
- l.setContentHeight(height);
- } else {
- l.setContentHeight(contentHeight);
- }
+ l.setContentHeight(height);
}
if (mIsSummaryWithChildren) {
mChildrenContainer.setActualHeight(height);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 5ca0866..9bf05cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -376,8 +376,7 @@
public boolean offerToKeepInParentForAnimation() {
//If the User dismissed the notification's parent, we want to keep it attached until the
//dismiss animation is ongoing. Therefore we don't want to remove it in the ShadeViewDiffer.
- if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_DISMISSAL_ANIMATION)
- && mView.isParentDismissed()) {
+ if (mView.isParentDismissed()) {
mView.setKeepInParentForDismissAnimation(true);
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 451d837..f432af2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -635,8 +635,7 @@
int hint;
if (mHeadsUpChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_HEADSUP)) {
hint = getViewHeight(VISIBLE_TYPE_HEADSUP);
- if (mHeadsUpRemoteInput != null && mHeadsUpRemoteInput.isAnimatingAppearance()
- && mHeadsUpRemoteInputController.isFocusAnimationFlagActive()) {
+ if (mHeadsUpRemoteInput != null && mHeadsUpRemoteInput.isAnimatingAppearance()) {
// While the RemoteInputView is animating its appearance, it should be allowed
// to overlap the hint, therefore no space is reserved for the hint during the
// appearance animation of the RemoteInputView
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt
new file mode 100644
index 0000000..54af107
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ActivatableNotificationViewBinder.kt
@@ -0,0 +1,98 @@
+/*
+ * 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.statusbar.notification.row.ui.viewbinder
+
+import android.view.MotionEvent
+import android.view.View
+import android.view.View.OnTouchListener
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.Gefingerpoken
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModel
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.launch
+
+/** Binds an [ActivatableNotificationView] to its [view model][ActivatableNotificationViewModel]. */
+object ActivatableNotificationViewBinder {
+
+ fun bind(
+ viewModel: ActivatableNotificationViewModel,
+ view: ActivatableNotificationView,
+ falsingManager: FalsingManager,
+ ) {
+ ExpandableOutlineViewBinder.bind(viewModel, view)
+ val touchHandler = TouchHandler(view, falsingManager)
+ view.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ viewModel.isTouchable.collect { isTouchable ->
+ touchHandler.isTouchEnabled = isTouchable
+ }
+ }
+ view.registerListenersWhileAttached(touchHandler)
+ }
+ }
+ }
+
+ private suspend fun ActivatableNotificationView.registerListenersWhileAttached(
+ touchHandler: TouchHandler,
+ ): Unit =
+ try {
+ setOnTouchListener(touchHandler)
+ setTouchHandler(touchHandler)
+ awaitCancellation()
+ } finally {
+ setTouchHandler(null)
+ setOnTouchListener(null)
+ }
+}
+
+private class TouchHandler(
+ private val view: ActivatableNotificationView,
+ private val falsingManager: FalsingManager,
+) : Gefingerpoken, OnTouchListener {
+
+ var isTouchEnabled = false
+
+ override fun onTouch(v: View, ev: MotionEvent): Boolean {
+ val result = false
+ if (ev.action == MotionEvent.ACTION_UP) {
+ view.setLastActionUpTime(ev.eventTime)
+ }
+ // With a11y, just do nothing.
+ if (!isTouchEnabled) {
+ return false
+ }
+ if (ev.action == MotionEvent.ACTION_UP) {
+ // If this is a false tap, capture the even so it doesn't result in a click.
+ val falseTap: Boolean = falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)
+ if (!falseTap && v is ActivatableNotificationView) {
+ v.onTap()
+ }
+ return falseTap
+ }
+ return result
+ }
+
+ override fun onInterceptTouchEvent(ev: MotionEvent): Boolean = false
+
+ /** Use [onTouch] instead. */
+ override fun onTouchEvent(ev: MotionEvent): Boolean = false
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ExpandableOutlineViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ExpandableOutlineViewBinder.kt
new file mode 100644
index 0000000..745ce77
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ExpandableOutlineViewBinder.kt
@@ -0,0 +1,13 @@
+package com.android.systemui.statusbar.notification.row.ui.viewbinder
+
+import com.android.systemui.statusbar.notification.row.ExpandableOutlineView
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ExpandableOutlineViewModel as ViewModel
+
+object ExpandableOutlineViewBinder {
+ fun bind(
+ viewModel: ViewModel,
+ view: ExpandableOutlineView,
+ ) {
+ ExpandableViewBinder.bind(viewModel, view)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ExpandableViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ExpandableViewBinder.kt
new file mode 100644
index 0000000..49cfb576
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/ExpandableViewBinder.kt
@@ -0,0 +1,8 @@
+package com.android.systemui.statusbar.notification.row.ui.viewbinder
+
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ExpandableViewModel as ViewModel
+
+object ExpandableViewBinder {
+ fun bind(viewModel: ViewModel, view: ExpandableView) {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModel.kt
new file mode 100644
index 0000000..f46d424
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModel.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.statusbar.notification.row.ui.viewmodel
+
+import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor
+import dagger.Module
+import dagger.Provides
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/** ViewModel for [com.android.systemui.statusbar.notification.row.ActivatableNotificationView]. */
+interface ActivatableNotificationViewModel : ExpandableOutlineViewModel {
+ /** Does the view react to touches? */
+ val isTouchable: Flow<Boolean>
+
+ companion object {
+ operator fun invoke(
+ a11yInteractor: AccessibilityInteractor,
+ ): ActivatableNotificationViewModel = ActivatableNotificationViewModelImpl(a11yInteractor)
+ }
+}
+
+private class ActivatableNotificationViewModelImpl(
+ a11yInteractor: AccessibilityInteractor,
+) : ActivatableNotificationViewModel {
+ override val isTouchable: Flow<Boolean> =
+ // If a11y touch exploration is enabled, then the activatable view should ignore touches
+ a11yInteractor.isTouchExplorationEnabled.map { !it }
+}
+
+@Module
+object ActivatableNotificationViewModelModule {
+ @Provides
+ fun provideViewModel(interactor: AccessibilityInteractor) =
+ ActivatableNotificationViewModel(interactor)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ExpandableOutlineViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ExpandableOutlineViewModel.kt
new file mode 100644
index 0000000..5904c77
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ExpandableOutlineViewModel.kt
@@ -0,0 +1,4 @@
+package com.android.systemui.statusbar.notification.row.ui.viewmodel
+
+/** ViewModel for [com.android.systemui.statusbar.notification.row.ExpandableOutlineView]. */
+interface ExpandableOutlineViewModel : ExpandableViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ExpandableViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ExpandableViewModel.kt
new file mode 100644
index 0000000..5efaf04
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ExpandableViewModel.kt
@@ -0,0 +1,4 @@
+package com.android.systemui.statusbar.notification.row.ui.viewmodel
+
+/** ViewModel for [com.android.systemui.statusbar.notification.row.ExpandableView]. */
+interface ExpandableViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt
index 8ba65f7..014406f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractor.kt
@@ -16,10 +16,14 @@
package com.android.systemui.statusbar.notification.shelf.domain.interactor
+import android.os.PowerManager
import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationShelf
+import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
+import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
@@ -31,6 +35,9 @@
constructor(
private val keyguardRepository: KeyguardRepository,
private val deviceEntryFaceAuthRepository: DeviceEntryFaceAuthRepository,
+ private val centralSurfaces: CentralSurfaces,
+ private val systemClock: SystemClock,
+ private val keyguardTransitionController: LockscreenShadeTransitionController,
) {
/** Is the shelf showing on the keyguard? */
val isShowingOnKeyguard: Flow<Boolean>
@@ -45,4 +52,14 @@
) { isKeyguardShowing, isBypassEnabled ->
isKeyguardShowing && isBypassEnabled
}
+
+ /** Transition keyguard to the locked shade, triggered by the shelf. */
+ fun goToLockedShadeFromShelf() {
+ centralSurfaces.wakeUpIfDozing(
+ systemClock.uptimeMillis(),
+ "SHADE_CLICK",
+ PowerManager.WAKE_REASON_GESTURE,
+ )
+ keyguardTransitionController.goToLockedShade(null)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
index b190cf6..c823189 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
@@ -17,10 +17,8 @@
package com.android.systemui.statusbar.notification.shelf.ui.viewbinder
import android.view.View
-import android.view.accessibility.AccessibilityManager
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.lifecycle.repeatWhenAttached
@@ -28,19 +26,17 @@
import com.android.systemui.statusbar.LegacyNotificationShelfControllerImpl
import com.android.systemui.statusbar.NotificationShelf
import com.android.systemui.statusbar.NotificationShelfController
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController
-import com.android.systemui.statusbar.notification.row.ExpandableOutlineViewController
-import com.android.systemui.statusbar.notification.row.ExpandableViewController
+import com.android.systemui.statusbar.notification.row.ui.viewbinder.ActivatableNotificationViewBinder
import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel
import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.phone.NotificationIconContainer
-import com.android.systemui.statusbar.phone.NotificationTapHelper
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
import com.android.systemui.util.kotlin.getValue
import dagger.Lazy
import javax.inject.Inject
+import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -57,11 +53,9 @@
private val shelf: NotificationShelf,
private val viewModel: NotificationShelfViewModel,
featureFlags: FeatureFlags,
- private val notifTapHelperFactory: NotificationTapHelper.Factory,
- private val a11yManager: AccessibilityManager,
private val falsingManager: FalsingManager,
- private val falsingCollector: FalsingCollector,
hostControllerLazy: Lazy<NotificationStackScrollLayoutController>,
+ private val notificationIconAreaController: NotificationIconAreaController,
) : NotificationShelfController {
private val hostController: NotificationStackScrollLayoutController by hostControllerLazy
@@ -78,43 +72,28 @@
}
fun init() {
- NotificationShelfViewBinder.bind(viewModel, shelf)
-
- ActivatableNotificationViewController(
- shelf,
- notifTapHelperFactory,
- ExpandableOutlineViewController(shelf, ExpandableViewController(shelf)),
- a11yManager,
- falsingManager,
- falsingCollector,
- )
- .init()
+ NotificationShelfViewBinder.bind(viewModel, shelf, falsingManager)
hostController.setShelf(shelf)
hostController.setOnNotificationRemovedListener { child, _ ->
view.requestRoundnessResetFor(child)
}
+ notificationIconAreaController.setShelfIcons(shelf.shelfIcons)
}
override val intrinsicHeight: Int
- get() = shelf.intrinsicHeight
+ get() = unsupported
override val shelfIcons: NotificationIconContainer
- get() = shelf.shelfIcons
+ get() = unsupported
override fun canModifyColorOfNotifications(): Boolean = unsupported
- override fun setOnActivatedListener(listener: ActivatableNotificationView.OnActivatedListener) {
- shelf.setOnActivatedListener(listener)
- }
-
override fun bind(
ambientState: AmbientState,
notificationStackScrollLayoutController: NotificationStackScrollLayoutController,
) = unsupported
- override fun setOnClickListener(listener: View.OnClickListener) {
- shelf.setOnClickListener(listener)
- }
+ override fun setOnClickListener(listener: View.OnClickListener) = unsupported
private val unsupported: Nothing
get() = NotificationShelfController.throwIllegalFlagStateError(expected = true)
@@ -122,14 +101,32 @@
/** Binds a [NotificationShelf] to its backend. */
object NotificationShelfViewBinder {
- fun bind(viewModel: NotificationShelfViewModel, shelf: NotificationShelf) {
+ fun bind(
+ viewModel: NotificationShelfViewModel,
+ shelf: NotificationShelf,
+ falsingManager: FalsingManager,
+ ) {
+ ActivatableNotificationViewBinder.bind(viewModel, shelf, falsingManager)
shelf.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.canModifyColorOfNotifications
.onEach(shelf::setCanModifyColorOfNotifications)
.launchIn(this)
viewModel.isClickable.onEach(shelf::setCanInteract).launchIn(this)
+ registerViewListenersWhileAttached(shelf, viewModel)
}
}
}
+
+ private suspend fun registerViewListenersWhileAttached(
+ shelf: NotificationShelf,
+ viewModel: NotificationShelfViewModel,
+ ) {
+ try {
+ shelf.setOnClickListener { viewModel.onShelfClicked() }
+ awaitCancellation()
+ } finally {
+ shelf.setOnClickListener(null)
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt
index 5e297c8..fb19443 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.shelf.ui.viewmodel
import com.android.systemui.statusbar.NotificationShelf
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModel
import com.android.systemui.statusbar.notification.shelf.domain.interactor.NotificationShelfInteractor
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
import javax.inject.Inject
@@ -29,7 +30,8 @@
@Inject
constructor(
private val interactor: NotificationShelfInteractor,
-) {
+ activatableViewModel: ActivatableNotificationViewModel,
+) : ActivatableNotificationViewModel by activatableViewModel {
/** Is the shelf allowed to be clickable when it has content? */
val isClickable: Flow<Boolean>
get() = interactor.isShowingOnKeyguard
@@ -37,4 +39,9 @@
/** Is the shelf allowed to modify the color of notifications in the host layout? */
val canModifyColorOfNotifications: Flow<Boolean>
get() = interactor.isShelfStatic.map { static -> !static }
+
+ /** Notifies that the user has clicked the shelf. */
+ fun onShelfClicked() {
+ interactor.goToLockedShadeFromShelf()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 77ede04..ae7c216 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -34,7 +34,6 @@
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController;
@@ -65,7 +64,6 @@
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private int mScrollY;
private boolean mDimmed;
- private ActivatableNotificationView mActivatedChild;
private float mOverScrollTopAmount;
private float mOverScrollBottomAmount;
private boolean mDozing;
@@ -360,14 +358,6 @@
mHideSensitive = hideSensitive;
}
- /**
- * In dimmed mode, a child can be activated, which happens on the first tap of the double-tap
- * interaction. This child is then scaled normally and its background is fully opaque.
- */
- public void setActivatedChild(ActivatableNotificationView activatedChild) {
- mActivatedChild = activatedChild;
- }
-
public boolean isDimmed() {
// While we are expanding from pulse, we want the notifications not to be dimmed, otherwise
// you'd see the difference to the pulsing notification
@@ -382,10 +372,6 @@
return mHideSensitive;
}
- public ActivatableNotificationView getActivatedChild() {
- return mActivatedChild;
- }
-
public void setOverScrollAmount(float amount, boolean onTop) {
if (onTop) {
mOverScrollTopAmount = amount;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index af608a7..555d502 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -4469,24 +4469,6 @@
}
}
- /**
- * See {@link AmbientState#setActivatedChild}.
- */
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void setActivatedChild(ActivatableNotificationView activatedChild) {
- mAmbientState.setActivatedChild(activatedChild);
- if (mAnimationsEnabled) {
- mActivateNeedsAnimation = true;
- mNeedsAnimation = true;
- }
- requestChildrenUpdate();
- }
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public ActivatableNotificationView getActivatedChild() {
- return mAmbientState.getActivatedChild();
- }
-
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void applyCurrentState() {
int numChildren = getChildCount();
@@ -5137,6 +5119,15 @@
requestChildrenUpdate();
}
+ @Nullable
+ public ExpandableView getShelf() {
+ if (NotificationShelfController.checkRefactorFlagEnabled(mAmbientState.getFeatureFlags())) {
+ return mShelf;
+ } else {
+ return null;
+ }
+ }
+
public void setShelf(NotificationShelf shelf) {
if (!NotificationShelfController.checkRefactorFlagEnabled(
mAmbientState.getFeatureFlags())) {
@@ -5236,7 +5227,6 @@
void onStatePostChange(boolean fromShadeLocked) {
boolean onKeyguard = onKeyguard();
- mAmbientState.setActivatedChild(null);
mAmbientState.setDimmed(onKeyguard);
if (mHeadsUpAppearanceController != null) {
@@ -5245,11 +5235,6 @@
setDimmed(onKeyguard, fromShadeLocked);
setExpandingEnabled(!onKeyguard);
- ActivatableNotificationView activatedChild = getActivatedChild();
- setActivatedChild(null);
- if (activatedChild != null) {
- activatedChild.makeInactive(false /* animate */);
- }
updateFooter();
requestChildrenUpdate();
onUpdateRowStates();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 1c8727f..e2f93ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -180,7 +180,6 @@
private final SeenNotificationsProvider mSeenNotificationsProvider;
private NotificationStackScrollLayout mView;
- private boolean mFadeNotificationsOnDismiss;
private NotificationSwipeHelper mSwipeHelper;
@Nullable
private Boolean mHistoryEnabled;
@@ -548,7 +547,7 @@
public boolean updateSwipeProgress(View animView, boolean dismissable,
float swipeProgress) {
// Returning true prevents alpha fading.
- return !mFadeNotificationsOnDismiss;
+ return false;
}
@Override
@@ -773,7 +772,6 @@
mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
- mFadeNotificationsOnDismiss = mFeatureFlags.isEnabled(Flags.NOTIFICATION_DISMISSAL_FADE);
if (!mUseRoundnessSourceTypes) {
mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate);
mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded);
@@ -1370,14 +1368,6 @@
mView.onUpdateRowStates();
}
- public ActivatableNotificationView getActivatedChild() {
- return mView.getActivatedChild();
- }
-
- public void setActivatedChild(ActivatableNotificationView view) {
- mView.setActivatedChild(view);
- }
-
public void runAfterAnimationFinished(Runnable r) {
mView.runAfterAnimationFinished(r);
}
@@ -1600,6 +1590,14 @@
mView.setShelf(shelf);
}
+ public int getShelfHeight() {
+ if (!NotificationShelfController.checkRefactorFlagEnabled(mFeatureFlags)) {
+ return 0;
+ }
+ ExpandableView shelf = mView.getShelf();
+ return shelf == null ? 0 : shelf.getIntrinsicHeight();
+ }
+
/**
* Enum for UiEvent logged from this class
*/
@@ -1942,8 +1940,7 @@
public void setNotifStats(@NonNull NotifStats notifStats) {
mNotifStats = notifStats;
mView.setHasFilteredOutSeenNotifications(
- mNotifPipelineFlags.getShouldFilterUnseenNotifsOnKeyguard()
- && mSeenNotificationsProvider.getHasFilteredOutSeenNotifications());
+ mSeenNotificationsProvider.getHasFilteredOutSeenNotifications());
updateFooter();
updateShowEmptyShadeView();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index b1fb13e0..3060473 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -126,7 +126,7 @@
updateHeadsUpStates(algorithmState, ambientState);
updatePulsingStates(algorithmState, ambientState);
- updateDimmedActivatedHideSensitive(ambientState, algorithmState);
+ updateDimmedAndHideSensitive(ambientState, algorithmState);
updateClipping(algorithmState, ambientState);
updateSpeedBumpState(algorithmState, speedBumpIndex);
updateShelfState(algorithmState, ambientState);
@@ -341,25 +341,17 @@
}
}
- /**
- * Updates the dimmed, activated and hiding sensitive states of the children.
- */
- private void updateDimmedActivatedHideSensitive(AmbientState ambientState,
- StackScrollAlgorithmState algorithmState) {
+ /** Updates the dimmed and hiding sensitive states of the children. */
+ private void updateDimmedAndHideSensitive(AmbientState ambientState,
+ StackScrollAlgorithmState algorithmState) {
boolean dimmed = ambientState.isDimmed();
boolean hideSensitive = ambientState.isHideSensitive();
- View activatedChild = ambientState.getActivatedChild();
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
ExpandableViewState childViewState = child.getViewState();
childViewState.dimmed = dimmed;
childViewState.hideSensitive = hideSensitive;
- boolean isActivatedChild = activatedChild == child;
- if (dimmed && isActivatedChild) {
- childViewState.setZTranslation(childViewState.getZTranslation()
- + 2.0f * ambientState.getZDistanceBetweenElements());
- }
}
}
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 3a1272f..b15d241 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -48,9 +48,9 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.qs.QSPanelController;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.NotificationShadeWindowViewController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.LightRevealScrim;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.util.Compile;
@@ -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;
@@ -212,13 +212,14 @@
/**
* Wakes up the device if the device was dozing.
*/
- void wakeUpIfDozing(long time, View where, String why, @PowerManager.WakeReason int wakeReason);
+ void wakeUpIfDozing(long time, String why, @PowerManager.WakeReason int wakeReason);
NotificationShadeWindowView getNotificationShadeWindowView();
NotificationShadeWindowViewController getNotificationShadeWindowViewController();
- NotificationPanelViewController getNotificationPanelViewController();
+ /** */
+ ShadeViewController getShadeViewController();
/** Get the Keyguard Message Area that displays auth messages. */
AuthKeyguardMessageArea getKeyguardMessageArea();
@@ -430,9 +431,6 @@
void collapseShade();
- /** Collapse the shade, but conditional on a flag specific to the trigger of a bugreport. */
- void collapseShadeForBugreport();
-
int getWakefulnessState();
boolean isScreenFullyOff();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 8b6617b..c0a7a34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -54,9 +54,9 @@
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.CameraLauncher;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.QuickSettingsController;
import com.android.systemui.shade.ShadeController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
@@ -80,7 +80,7 @@
private final Context mContext;
private final com.android.systemui.shade.ShadeController mShadeController;
private final CommandQueue mCommandQueue;
- private final NotificationPanelViewController mNotificationPanelViewController;
+ private final ShadeViewController mShadeViewController;
private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private final MetricsLogger mMetricsLogger;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -117,7 +117,7 @@
@Main Resources resources,
ShadeController shadeController,
CommandQueue commandQueue,
- NotificationPanelViewController notificationPanelViewController,
+ ShadeViewController shadeViewController,
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
MetricsLogger metricsLogger,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -144,7 +144,7 @@
mContext = context;
mShadeController = shadeController;
mCommandQueue = commandQueue;
- mNotificationPanelViewController = notificationPanelViewController;
+ mShadeViewController = shadeViewController;
mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
mMetricsLogger = metricsLogger;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -218,7 +218,7 @@
return;
}
- mNotificationPanelViewController.expandToNotifications();
+ mShadeViewController.expandToNotifications();
}
@Override
@@ -234,7 +234,7 @@
// Settings are not available in setup
if (!mDeviceProvisionedController.isCurrentUserSetup()) return;
- mNotificationPanelViewController.expandToQs();
+ mShadeViewController.expandToQs();
}
@Override
@@ -300,7 +300,7 @@
}
}
- mNotificationPanelViewController.disableHeader(state1, state2, animate);
+ mShadeViewController.disableHeader(state1, state2, animate);
}
/**
@@ -322,22 +322,22 @@
if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key.getKeyCode()) {
mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP);
- mNotificationPanelViewController.collapse(
+ mShadeViewController.collapse(
false /* delayed */, 1.0f /* speedUpFactor */);
} else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key.getKeyCode()) {
mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
- if (mNotificationPanelViewController.isFullyCollapsed()) {
+ if (mShadeViewController.isFullyCollapsed()) {
if (mVibrateOnOpening) {
mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
}
- mNotificationPanelViewController.expand(true /* animate */);
+ mShadeViewController.expand(true /* animate */);
mNotificationStackScrollLayoutController.setWillExpand(true);
mHeadsUpManager.unpinAll(true /* userUnpinned */);
mMetricsLogger.count("panel_open", 1);
} else if (!mQsController.getExpanded()
- && !mNotificationPanelViewController.isExpanding()) {
+ && !mShadeViewController.isExpanding()) {
mQsController.flingQs(0 /* velocity */,
- NotificationPanelViewController.FLING_EXPAND);
+ ShadeViewController.FLING_EXPAND);
mMetricsLogger.count("panel_open_qs", 1);
}
}
@@ -355,7 +355,7 @@
return;
}
if (!mCameraLauncherLazy.get().canCameraGestureBeLaunched(
- mNotificationPanelViewController.getBarState())) {
+ mShadeViewController.getBarState())) {
if (CentralSurfaces.DEBUG_CAMERA_LIFT) {
Slog.d(CentralSurfaces.TAG, "Can't launch camera right now");
}
@@ -394,7 +394,7 @@
mStatusBarKeyguardViewManager.reset(true /* hide */);
}
mCameraLauncherLazy.get().launchCamera(source,
- mNotificationPanelViewController.isFullyCollapsed());
+ mShadeViewController.isFullyCollapsed());
mCentralSurfaces.updateScrimController();
} else {
// We need to defer the camera launch until the screen comes on, since otherwise
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 0960efb..b3953a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -193,6 +193,8 @@
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shade.ShadeLogger;
+import com.android.systemui.shade.ShadeSurface;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CircleReveal;
@@ -230,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;
@@ -505,7 +508,7 @@
/** Controller for the Shade. */
@VisibleForTesting
- NotificationPanelViewController mNotificationPanelViewController;
+ ShadeSurface mShadeSurface;
private final ShadeLogger mShadeLogger;
// settings
@@ -698,9 +701,9 @@
@Override
public void onBackProgressed(BackEvent event) {
if (shouldBackBeHandled()) {
- if (mNotificationPanelViewController.canBeCollapsed()) {
+ if (mShadeSurface.canBeCollapsed()) {
float fraction = event.getProgress();
- mNotificationPanelViewController.onBackProgressed(fraction);
+ mShadeSurface.onBackProgressed(fraction);
}
}
}
@@ -951,11 +954,6 @@
mUiModeManager = mContext.getSystemService(UiModeManager.class);
mBubblesOptional.ifPresent(this::initBubbles);
- // Do not restart System UI when the bugreport flag changes.
- mFeatureFlags.addListener(Flags.LEAVE_SHADE_OPEN_FOR_BUGREPORT, event -> {
- event.requestNoRestart();
- });
-
mStatusBarSignalPolicy.init();
mKeyguardIndicationController.init();
@@ -1090,7 +1088,7 @@
this,
mStatusBarKeyguardViewManager,
mNotificationShadeWindowViewController,
- mNotificationPanelViewController,
+ mShadeSurface,
mAmbientIndicationContainer);
updateLightRevealScrimVisibility();
@@ -1253,7 +1251,9 @@
// TODO: Deal with the ugliness that comes from having some of the status bar broken out
// into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
- mNotificationIconAreaController.setupShelf(mNotificationShelfController);
+ if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
+ mNotificationIconAreaController.setupShelf(mNotificationShelfController);
+ }
mShadeExpansionStateManager.addExpansionListener(mWakeUpCoordinator);
// Allow plugins to reference DarkIconDispatcher and StatusBarStateController
@@ -1274,7 +1274,7 @@
// re-display the notification panel if necessary (for example, if
// a heads-up notification was being displayed and should continue being
// displayed).
- mNotificationPanelViewController.updateExpansionAndVisibility();
+ mShadeSurface.updateExpansionAndVisibility();
setBouncerShowingForStatusBarComponents(mBouncerShowing);
checkBarModes();
});
@@ -1349,7 +1349,7 @@
mScreenOffAnimationController.initialize(this, mLightRevealScrim);
updateLightRevealScrimVisibility();
- mNotificationPanelViewController.initDependencies(
+ mShadeSurface.initDependencies(
this,
mGestureRec,
mShadeController::makeExpandedInvisible,
@@ -1357,8 +1357,13 @@
mHeadsUpManager);
BackDropView backdrop = mNotificationShadeWindowView.findViewById(R.id.backdrop);
- mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front),
- backdrop.findViewById(R.id.backdrop_back), mScrimController, mLockscreenWallpaper);
+ if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
+ mMediaManager.setup(null, null, null, mScrimController, null);
+ } else {
+ mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front),
+ backdrop.findViewById(R.id.backdrop_back), mScrimController,
+ mLockscreenWallpaper);
+ }
float maxWallpaperZoom = mContext.getResources().getFloat(
com.android.internal.R.dimen.config_wallpaperMaxScale);
mNotificationShadeDepthControllerLazy.get().addListener(depth -> {
@@ -1386,7 +1391,7 @@
.build());
mBrightnessMirrorController = new BrightnessMirrorController(
mNotificationShadeWindowView,
- mNotificationPanelViewController,
+ mShadeSurface,
mNotificationShadeDepthControllerLazy.get(),
mBrightnessSliderFactory,
(visible) -> {
@@ -1486,7 +1491,7 @@
|| !mKeyguardStateController.canDismissLockScreen()
|| mKeyguardViewMediator.isAnySimPinSecure()
|| (mQsController.getExpanded() && trackingTouch)
- || mNotificationPanelViewController.getBarState() == StatusBarState.SHADE_LOCKED) {
+ || mShadeSurface.getBarState() == StatusBarState.SHADE_LOCKED) {
return;
}
@@ -1506,8 +1511,8 @@
boolean tracking = event.getTracking();
dispatchPanelExpansionForKeyguardDismiss(fraction, tracking);
- if (getNotificationPanelViewController() != null) {
- getNotificationPanelViewController().updateSystemUiStateFlags();
+ if (getShadeViewController() != null) {
+ getShadeViewController().updateSystemUiStateFlags();
}
if (fraction == 0 || fraction == 1) {
@@ -1563,7 +1568,6 @@
mNotifListContainer,
mHeadsUpManager,
mJankMonitor);
- mNotificationShelfController.setOnActivatedListener(mPresenter);
mRemoteInputManager.addControllerCallback(mNotificationShadeWindowController);
mStackScrollerController.setNotificationActivityStarter(mNotificationActivityStarter);
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
@@ -1590,12 +1594,10 @@
* Ask the display to wake up if currently dozing, else do nothing
*
* @param time when to wake up
- * @param where the view requesting the wakeup
* @param why the reason for the wake up
*/
@Override
- public void wakeUpIfDozing(long time, View where, String why,
- @PowerManager.WakeReason int wakeReason) {
+ public void wakeUpIfDozing(long time, String why, @PowerManager.WakeReason int wakeReason) {
if (mDozing && mScreenOffAnimationController.allowWakeUpIfDozing()) {
mPowerManager.wakeUp(
time, wakeReason, "com.android.systemui:" + why);
@@ -1631,16 +1633,19 @@
}
}
mCentralSurfacesComponent = mCentralSurfacesComponentFactory.create();
- mFragmentService.addFragmentInstantiationProvider(mCentralSurfacesComponent);
+ mFragmentService.addFragmentInstantiationProvider(
+ CollapsedStatusBarFragment.class,
+ mCentralSurfacesComponent::createCollapsedStatusBarFragment);
mNotificationShadeWindowView = mCentralSurfacesComponent.getNotificationShadeWindowView();
mNotificationShadeWindowViewController = mCentralSurfacesComponent
.getNotificationShadeWindowViewController();
mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
mNotificationShadeWindowViewController.setupExpandedStatusBar();
- mNotificationPanelViewController =
+ NotificationPanelViewController npvc =
mCentralSurfacesComponent.getNotificationPanelViewController();
- mShadeController.setNotificationPanelViewController(mNotificationPanelViewController);
+ mShadeSurface = npvc;
+ mShadeController.setNotificationPanelViewController(npvc);
mShadeController.setNotificationShadeWindowViewController(
mNotificationShadeWindowViewController);
mCentralSurfacesComponent.getLockIconViewController().init();
@@ -1706,7 +1711,7 @@
});
mKeyguardViewMediator.registerCentralSurfaces(
/* statusBar= */ this,
- mNotificationPanelViewController,
+ mShadeSurface,
mShadeExpansionStateManager,
mBiometricUnlockController,
mStackScroller,
@@ -1734,8 +1739,8 @@
}
@Override
- public NotificationPanelViewController getNotificationPanelViewController() {
- return mNotificationPanelViewController;
+ public ShadeViewController getShadeViewController() {
+ return mShadeSurface;
}
@Override
@@ -2092,16 +2097,16 @@
}
if (start) {
- mNotificationPanelViewController.startWaitingForExpandGesture();
+ mShadeSurface.startWaitingForExpandGesture();
} else {
- mNotificationPanelViewController.stopWaitingForExpandGesture(cancel, velocity);
+ mShadeSurface.stopWaitingForExpandGesture(cancel, velocity);
}
}
@Override
public void animateCollapseQuickSettings() {
if (mState == StatusBarState.SHADE) {
- mNotificationPanelViewController.collapse(
+ mShadeSurface.collapse(
true, false /* delayed */, 1.0f /* speedUpFactor */);
}
}
@@ -2726,7 +2731,7 @@
*/
@Override
public void setLockscreenUser(int newUserId) {
- if (mLockscreenWallpaper != null) {
+ if (mLockscreenWallpaper != null && !mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
mLockscreenWallpaper.setCurrentUser(newUserId);
}
mScrimController.setCurrentUser(newUserId);
@@ -2752,8 +2757,8 @@
mStatusBarWindowController.refreshStatusBarHeight();
}
- if (mNotificationPanelViewController != null) {
- mNotificationPanelViewController.updateResources();
+ if (mShadeSurface != null) {
+ mShadeSurface.updateResources();
}
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.updateResources();
@@ -3011,7 +3016,7 @@
public void showKeyguardImpl() {
Trace.beginSection("CentralSurfaces#showKeyguard");
if (mKeyguardStateController.isLaunchTransitionFadingAway()) {
- mNotificationPanelViewController.cancelAnimation();
+ mShadeSurface.cancelAnimation();
onLaunchTransitionFadingEnded();
}
mMessageRouter.cancelMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
@@ -3030,7 +3035,7 @@
}
private void onLaunchTransitionFadingEnded() {
- mNotificationPanelViewController.resetAlpha();
+ mShadeSurface.resetAlpha();
mCameraLauncherLazy.get().setLaunchingAffordance(false);
releaseGestureWakeLock();
runLaunchTransitionEndRunnable();
@@ -3060,8 +3065,8 @@
}
updateScrimController();
mPresenter.updateMediaMetaData(false, true);
- mNotificationPanelViewController.resetAlpha();
- mNotificationPanelViewController.fadeOut(
+ mShadeSurface.resetAlpha();
+ mShadeSurface.fadeOut(
FADE_KEYGUARD_START_DELAY, FADE_KEYGUARD_DURATION,
this::onLaunchTransitionFadingEnded);
mCommandQueue.appTransitionStarting(mDisplayId, SystemClock.uptimeMillis(),
@@ -3093,7 +3098,7 @@
Log.w(TAG, "Launch transition: Timeout!");
mCameraLauncherLazy.get().setLaunchingAffordance(false);
releaseGestureWakeLock();
- mNotificationPanelViewController.resetViews(false /* animate */);
+ mShadeSurface.resetViews(false /* animate */);
}
private void runLaunchTransitionEndRunnable() {
@@ -3133,7 +3138,7 @@
// Disable layout transitions in navbar for this transition because the load is just
// too heavy for the CPU and GPU on any device.
mNavigationBarController.disableAnimationsDuringHide(mDisplayId, delay);
- } else if (!mNotificationPanelViewController.isCollapsing()) {
+ } else if (!mShadeSurface.isCollapsing()) {
mShadeController.instantCollapseShade();
}
@@ -3145,9 +3150,9 @@
mMessageRouter.cancelMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
releaseGestureWakeLock();
mCameraLauncherLazy.get().setLaunchingAffordance(false);
- mNotificationPanelViewController.resetAlpha();
- mNotificationPanelViewController.resetTranslation();
- mNotificationPanelViewController.resetViewGroupFade();
+ mShadeSurface.resetAlpha();
+ mShadeSurface.resetTranslation();
+ mShadeSurface.resetViewGroupFade();
updateDozingState();
updateScrimController();
Trace.endSection();
@@ -3249,7 +3254,7 @@
boolean animate = (!mDozing && shouldAnimateDozeWakeup())
|| (mDozing && mDozeParameters.shouldControlScreenOff() && keyguardVisibleOrWillBe);
- mNotificationPanelViewController.setDozing(mDozing, animate);
+ mShadeSurface.setDozing(mDozing, animate);
updateQsExpansionEnabled();
Trace.endSection();
}
@@ -3329,16 +3334,16 @@
return true;
}
if (mQsController.getExpanded()) {
- mNotificationPanelViewController.animateCollapseQs(false);
+ mShadeSurface.animateCollapseQs(false);
return true;
}
- if (mNotificationPanelViewController.closeUserSwitcherIfOpen()) {
+ if (mShadeSurface.closeUserSwitcherIfOpen()) {
return true;
}
if (shouldBackBeHandled()) {
- if (mNotificationPanelViewController.canBeCollapsed()) {
+ if (mShadeSurface.canBeCollapsed()) {
// this is the Shade dismiss animation, so make sure QQS closes when it ends.
- mNotificationPanelViewController.onBackPressed();
+ mShadeSurface.onBackPressed();
mShadeController.animateCollapseShade();
}
return true;
@@ -3481,7 +3486,7 @@
mStatusBarHideIconsForBouncerManager.setBouncerShowingAndTriggerUpdate(bouncerShowing);
mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
if (mBouncerShowing) {
- wakeUpIfDozing(SystemClock.uptimeMillis(), null, "BOUNCER_VISIBLE",
+ wakeUpIfDozing(SystemClock.uptimeMillis(), "BOUNCER_VISIBLE",
PowerManager.WAKE_REASON_GESTURE);
}
updateScrimController();
@@ -3514,8 +3519,8 @@
if (mPhoneStatusBarViewController != null) {
mPhoneStatusBarViewController.setImportantForAccessibility(importance);
}
- mNotificationPanelViewController.setImportantForAccessibility(importance);
- mNotificationPanelViewController.setBouncerShowing(bouncerShowing);
+ mShadeSurface.setImportantForAccessibility(importance);
+ mShadeSurface.setBouncerShowing(bouncerShowing);
}
/**
@@ -3523,7 +3528,7 @@
*/
@Override
public void collapseShade() {
- if (mNotificationPanelViewController.isTracking()) {
+ if (mShadeSurface.isTracking()) {
mNotificationShadeWindowViewController.cancelCurrentTouch();
}
if (mPanelExpanded && mState == StatusBarState.SHADE) {
@@ -3531,13 +3536,6 @@
}
}
- @Override
- public void collapseShadeForBugreport() {
- if (!mFeatureFlags.isEnabled(Flags.LEAVE_SHADE_OPEN_FOR_BUGREPORT)) {
- collapseShade();
- }
- }
-
@VisibleForTesting
final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
@Override
@@ -3634,7 +3632,7 @@
}
}
- mNotificationPanelViewController.setWillPlayDelayedDozeAmountAnimation(
+ mShadeSurface.setWillPlayDelayedDozeAmountAnimation(
mShouldDelayWakeUpAnimation);
mWakeUpCoordinator.setWakingUp(
/* wakingUp= */ true,
@@ -3676,12 +3674,12 @@
// So if AOD is off or unsupported we need to trigger these updates at screen on
// when the keyguard is occluded.
mLockscreenUserManager.updatePublicMode();
- mNotificationPanelViewController.getNotificationStackScrollLayoutController()
+ mShadeSurface.getNotificationStackScrollLayoutController()
.updateSensitivenessForOccludedWakeup();
}
if (mLaunchCameraWhenFinishedWaking) {
mCameraLauncherLazy.get().launchCamera(mLastCameraLaunchSource,
- mNotificationPanelViewController.isFullyCollapsed());
+ mShadeSurface.isFullyCollapsed());
mLaunchCameraWhenFinishedWaking = false;
}
if (mLaunchEmergencyActionWhenFinishedWaking) {
@@ -3712,7 +3710,7 @@
!mDozeParameters.shouldControlScreenOff(), !mDeviceInteractive,
!mDozeServiceHost.isPulsing(), mDeviceProvisionedController.isFrpActive());
- mNotificationPanelViewController.setTouchAndAnimationDisabled(disabled);
+ mShadeSurface.setTouchAndAnimationDisabled(disabled);
mNotificationIconAreaController.setAnimationsEnabled(!disabled);
}
@@ -3720,7 +3718,7 @@
@Override
public void onScreenTurningOn() {
mFalsingCollector.onScreenTurningOn();
- mNotificationPanelViewController.onScreenTurningOn();
+ mShadeSurface.onScreenTurningOn();
}
@Override
@@ -4364,7 +4362,7 @@
}
// We need the new R.id.keyguard_indication_area before recreating
// mKeyguardIndicationController
- mNotificationPanelViewController.onThemeChanged();
+ mShadeSurface.onThemeChanged();
if (mStatusBarKeyguardViewManager != null) {
mStatusBarKeyguardViewManager.onThemeChanged();
@@ -4410,7 +4408,7 @@
mNavigationBarController.touchAutoDim(mDisplayId);
Trace.beginSection("CentralSurfaces#updateKeyguardState");
if (mState == StatusBarState.KEYGUARD) {
- mNotificationPanelViewController.cancelPendingCollapse();
+ mShadeSurface.cancelPendingCollapse();
}
updateDozingState();
checkBarModes();
@@ -4436,7 +4434,7 @@
&& mDozeParameters.shouldControlScreenOff();
// resetting views is already done when going into doze, there's no need to
// reset them again when we're waking up
- mNotificationPanelViewController.resetViews(dozingAnimated && isDozing);
+ mShadeSurface.resetViews(dozingAnimated && isDozing);
updateQsExpansionEnabled();
mKeyguardViewMediator.setDozing(mDozing);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index 5196e10..89c3946 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -37,8 +37,8 @@
import com.android.systemui.doze.DozeLog;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowViewController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarState;
@@ -50,12 +50,12 @@
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.util.Assert;
+import dagger.Lazy;
+
import java.util.ArrayList;
import javax.inject.Inject;
-import dagger.Lazy;
-
/**
* Implementation of DozeHost for SystemUI.
*/
@@ -90,7 +90,7 @@
private final AuthController mAuthController;
private final NotificationIconAreaController mNotificationIconAreaController;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- private NotificationPanelViewController mNotificationPanel;
+ private ShadeViewController mNotificationPanel;
private View mAmbientIndicationContainer;
private CentralSurfaces mCentralSurfaces;
private boolean mAlwaysOnSuppressed;
@@ -141,7 +141,7 @@
CentralSurfaces centralSurfaces,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
NotificationShadeWindowViewController notificationShadeWindowViewController,
- NotificationPanelViewController notificationPanel,
+ ShadeViewController notificationPanel,
View ambientIndicationContainer) {
mCentralSurfaces = centralSurfaces;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 171e3d0..e705afc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -31,8 +31,8 @@
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeHeadsUpTracker;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.HeadsUpStatusBarView;
@@ -76,7 +76,7 @@
private final NotificationStackScrollLayoutController mStackScrollerController;
private final DarkIconDispatcher mDarkIconDispatcher;
- private final NotificationPanelViewController mNotificationPanelViewController;
+ private final ShadeViewController mShadeViewController;
private final NotificationRoundnessManager mNotificationRoundnessManager;
private final boolean mUseRoundnessSourceTypes;
private final Consumer<ExpandableNotificationRow>
@@ -118,7 +118,7 @@
KeyguardStateController keyguardStateController,
CommandQueue commandQueue,
NotificationStackScrollLayoutController stackScrollerController,
- NotificationPanelViewController notificationPanelViewController,
+ ShadeViewController shadeViewController,
NotificationRoundnessManager notificationRoundnessManager,
FeatureFlags featureFlags,
HeadsUpStatusBarView headsUpStatusBarView,
@@ -134,13 +134,13 @@
// has started pulling down the notification shade from the HUN and then the font size
// changes). We need to re-fetch these values since they're used to correctly display the
// HUN during this shade expansion.
- mTrackedChild = notificationPanelViewController.getShadeHeadsUpTracker()
+ mTrackedChild = shadeViewController.getShadeHeadsUpTracker()
.getTrackedHeadsUpNotification();
mAppearFraction = stackScrollerController.getAppearFraction();
mExpandedHeight = stackScrollerController.getExpandedHeight();
mStackScrollerController = stackScrollerController;
- mNotificationPanelViewController = notificationPanelViewController;
+ mShadeViewController = shadeViewController;
mStackScrollerController.setHeadsUpAppearanceController(this);
mClockView = clockView;
mOperatorNameViewOptional = operatorNameViewOptional;
@@ -179,7 +179,7 @@
}
private ShadeHeadsUpTracker getShadeHeadsUpTracker() {
- return mNotificationPanelViewController.getShadeHeadsUpTracker();
+ return mShadeViewController.getShadeHeadsUpTracker();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index c163a89..90a6d0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -27,7 +27,7 @@
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
-import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcherListView;
/**
@@ -84,7 +84,7 @@
private int mSplitShadeTargetTopMargin;
/**
- * @see NotificationPanelViewController#getExpandedFraction()
+ * @see ShadeViewController#getExpandedFraction()
*/
private float mPanelExpansion;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 2814e8d..e835c5ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -47,7 +47,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.shade.ShadeViewStateProvider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.StatusBarState;
@@ -69,6 +69,8 @@
import com.android.systemui.util.ViewController;
import com.android.systemui.util.settings.SecureSettings;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -76,8 +78,6 @@
import javax.inject.Inject;
-import kotlin.Unit;
-
/** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */
public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> {
private static final String TAG = "KeyguardStatusBarViewController";
@@ -104,8 +104,7 @@
private final StatusBarIconController mStatusBarIconController;
private final StatusBarIconController.TintedIconManager.Factory mTintedIconManagerFactory;
private final BatteryMeterViewController mBatteryMeterViewController;
- private final NotificationPanelViewController.NotificationPanelViewStateProvider
- mNotificationPanelViewStateProvider;
+ private final ShadeViewStateProvider mShadeViewStateProvider;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardBypassController mKeyguardBypassController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -274,8 +273,7 @@
StatusBarIconController statusBarIconController,
StatusBarIconController.TintedIconManager.Factory tintedIconManagerFactory,
BatteryMeterViewController batteryMeterViewController,
- NotificationPanelViewController.NotificationPanelViewStateProvider
- notificationPanelViewStateProvider,
+ ShadeViewStateProvider shadeViewStateProvider,
KeyguardStateController keyguardStateController,
KeyguardBypassController bypassController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -299,7 +297,7 @@
mStatusBarIconController = statusBarIconController;
mTintedIconManagerFactory = tintedIconManagerFactory;
mBatteryMeterViewController = batteryMeterViewController;
- mNotificationPanelViewStateProvider = notificationPanelViewStateProvider;
+ mShadeViewStateProvider = shadeViewStateProvider;
mKeyguardStateController = keyguardStateController;
mKeyguardBypassController = bypassController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -470,7 +468,7 @@
/**
* Updates the {@link KeyguardStatusBarView} state based on what the
- * {@link NotificationPanelViewController.NotificationPanelViewStateProvider} and other
+ * {@link ShadeViewController.NotificationPanelViewStateProvider} and other
* controllers provide.
*/
public void updateViewState() {
@@ -479,7 +477,7 @@
}
float alphaQsExpansion = 1 - Math.min(
- 1, mNotificationPanelViewStateProvider.getLockscreenShadeDragProgress() * 2);
+ 1, mShadeViewStateProvider.getLockscreenShadeDragProgress() * 2);
float newAlpha;
if (mExplicitAlpha != -1) {
@@ -530,12 +528,12 @@
if (isKeyguardShowing()) {
// When on Keyguard, we hide the header as soon as we expanded close enough to the
// header
- alpha = mNotificationPanelViewStateProvider.getPanelViewExpandedHeight()
+ alpha = mShadeViewStateProvider.getPanelViewExpandedHeight()
/ (mView.getHeight() + mNotificationsHeaderCollideDistance);
} else {
// In SHADE_LOCKED, the top card is already really close to the header. Hide it as
// soon as we start translating the stack.
- alpha = mNotificationPanelViewStateProvider.getPanelViewExpandedHeight()
+ alpha = mShadeViewStateProvider.getPanelViewExpandedHeight()
/ mView.getHeight();
}
alpha = MathUtils.saturate(alpha);
@@ -585,7 +583,7 @@
void updateForHeadsUp(boolean animate) {
boolean showingKeyguardHeadsUp =
- isKeyguardShowing() && mNotificationPanelViewStateProvider.shouldHeadsUpBeVisible();
+ isKeyguardShowing() && mShadeViewStateProvider.shouldHeadsUpBeVisible();
if (mShowingKeyguardHeadsUp != showingKeyguardHeadsUp) {
mShowingKeyguardHeadsUp = showingKeyguardHeadsUp;
if (isKeyguardShowing()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index c16877a..c07b5e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -63,6 +63,11 @@
private static final String TAG = "LockscreenWallpaper";
+ // TODO(b/253507223): temporary; remove this
+ private static final String DISABLED_ERROR_MESSAGE = "Methods from LockscreenWallpaper.java "
+ + "should not be called in this version. The lock screen wallpaper should be "
+ + "managed by the WallpaperManagerService and not by this class.";
+
private final NotificationMediaManager mMediaManager;
private final WallpaperManager mWallpaperManager;
private final KeyguardUpdateMonitor mUpdateMonitor;
@@ -91,7 +96,7 @@
mMediaManager = mediaManager;
mH = mainHandler;
- if (iWallpaperManager != null) {
+ if (iWallpaperManager != null && !mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
// Service is disabled on some devices like Automotive
try {
iWallpaperManager.setLockWallpaperCallback(this);
@@ -102,6 +107,8 @@
}
public Bitmap getBitmap() {
+ assertLockscreenLiveWallpaperNotEnabled();
+
if (mCached) {
return mCache;
}
@@ -122,9 +129,8 @@
public LoaderResult loadBitmap(int currentUserId, UserHandle selectedUser) {
// May be called on any thread - only use thread safe operations.
- if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
- return LoaderResult.success(null);
- }
+ assertLockscreenLiveWallpaperNotEnabled();
+
if (!mWallpaperManager.isWallpaperSupported()) {
// When wallpaper is not supported, show the system wallpaper
@@ -164,6 +170,8 @@
}
public void setCurrentUser(int user) {
+ assertLockscreenLiveWallpaperNotEnabled();
+
if (user != mCurrentUserId) {
if (mSelectedUser == null || user != mSelectedUser.getIdentifier()) {
mCached = false;
@@ -173,6 +181,8 @@
}
public void setSelectedUser(UserHandle selectedUser) {
+ assertLockscreenLiveWallpaperNotEnabled();
+
if (Objects.equals(selectedUser, mSelectedUser)) {
return;
}
@@ -182,16 +192,18 @@
@Override
public void onWallpaperChanged() {
+ assertLockscreenLiveWallpaperNotEnabled();
// Called on Binder thread.
postUpdateWallpaper();
}
@Override
public void onWallpaperColorsChanged(WallpaperColors colors, int which, int userId) {
-
+ assertLockscreenLiveWallpaperNotEnabled();
}
private void postUpdateWallpaper() {
+ assertLockscreenLiveWallpaperNotEnabled();
if (mH == null) {
Log.wtfStack(TAG, "Trying to use LockscreenWallpaper before initialization.");
return;
@@ -199,11 +211,12 @@
mH.removeCallbacks(this);
mH.post(this);
}
-
@Override
public void run() {
// Called in response to onWallpaperChanged on the main thread.
+ assertLockscreenLiveWallpaperNotEnabled();
+
if (mLoader != null) {
mLoader.cancel(false /* interrupt */);
}
@@ -358,4 +371,16 @@
}
}
}
+
+ /**
+ * Feature b/253507223 will adapt the logic to always use the
+ * WallpaperManagerService to render the lock screen wallpaper.
+ * Methods of this class should not be called at all if the project flag is enabled.
+ * TODO(b/253507223) temporary assertion; remove this
+ */
+ private void assertLockscreenLiveWallpaperNotEnabled() {
+ if (mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
+ throw new IllegalStateException(DISABLED_ERROR_MESSAGE);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 057fa42..55dc188 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -23,6 +23,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -92,6 +93,8 @@
private final DemoModeController mDemoModeController;
+ private final FeatureFlags mFeatureFlags;
+
private int mAodIconAppearTranslation;
private boolean mAnimationsEnabled;
@@ -122,11 +125,12 @@
Optional<Bubbles> bubblesOptional,
DemoModeController demoModeController,
DarkIconDispatcher darkIconDispatcher,
- StatusBarWindowController statusBarWindowController,
+ FeatureFlags featureFlags, StatusBarWindowController statusBarWindowController,
ScreenOffAnimationController screenOffAnimationController) {
mContrastColorUtil = ContrastColorUtil.getInstance(context);
mContext = context;
mStatusBarStateController = statusBarStateController;
+ mFeatureFlags = featureFlags;
mStatusBarStateController.addCallback(this);
mMediaManager = notificationMediaManager;
mDozeParameters = dozeParameters;
@@ -192,9 +196,16 @@
}
public void setupShelf(NotificationShelfController notificationShelfController) {
+ NotificationShelfController.assertRefactorFlagDisabled(mFeatureFlags);
mShelfIcons = notificationShelfController.getShelfIcons();
}
+ public void setShelfIcons(NotificationIconContainer icons) {
+ if (NotificationShelfController.checkRefactorFlagEnabled(mFeatureFlags)) {
+ mShelfIcons = icons;
+ }
+ }
+
public void onDensityOrFontScaleChanged(Context context) {
updateIconLayoutParams(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index 62d302f..e6cb68f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -165,19 +165,19 @@
if (event.action == MotionEvent.ACTION_DOWN) {
// If the view that would receive the touch is disabled, just have status
// bar eat the gesture.
- if (!centralSurfaces.notificationPanelViewController.isViewEnabled) {
+ if (!centralSurfaces.shadeViewController.isViewEnabled) {
shadeLogger.logMotionEvent(event,
"onTouchForwardedFromStatusBar: panel view disabled")
return true
}
- if (centralSurfaces.notificationPanelViewController.isFullyCollapsed &&
+ if (centralSurfaces.shadeViewController.isFullyCollapsed &&
event.y < 1f) {
// b/235889526 Eat events on the top edge of the phone when collapsed
shadeLogger.logMotionEvent(event, "top edge touch ignored")
return true
}
}
- return centralSurfaces.notificationPanelViewController.handleExternalTouch(event)
+ return centralSurfaces.shadeViewController.handleExternalTouch(event)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index d3aa4bf..51c56a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -64,7 +64,7 @@
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.scrim.ScrimView;
-import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.statusbar.notification.stack.ViewState;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -649,7 +649,7 @@
calculateAndUpdatePanelExpansion();
}
- /** See {@link NotificationPanelViewController#setPanelScrimMinFraction(float)}. */
+ /** See {@link ShadeViewController#setPanelScrimMinFraction(float)}. */
public void setPanelScrimMinFraction(float minFraction) {
if (isNaN(minFraction)) {
throw new IllegalArgumentException("minFraction should not be NaN");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
index a7413d5..481cf3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.phone;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
@@ -34,7 +34,7 @@
public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener {
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final StatusBarWindowController mStatusBarWindowController;
- private final NotificationPanelViewController mNotificationPanelViewController;
+ private final ShadeViewController mShadeViewController;
private final KeyguardBypassController mKeyguardBypassController;
private final HeadsUpManagerPhone mHeadsUpManager;
private final StatusBarStateController mStatusBarStateController;
@@ -44,7 +44,7 @@
StatusBarHeadsUpChangeListener(
NotificationShadeWindowController notificationShadeWindowController,
StatusBarWindowController statusBarWindowController,
- NotificationPanelViewController notificationPanelViewController,
+ ShadeViewController shadeViewController,
KeyguardBypassController keyguardBypassController,
HeadsUpManagerPhone headsUpManager,
StatusBarStateController statusBarStateController,
@@ -52,7 +52,7 @@
mNotificationShadeWindowController = notificationShadeWindowController;
mStatusBarWindowController = statusBarWindowController;
- mNotificationPanelViewController = notificationPanelViewController;
+ mShadeViewController = shadeViewController;
mKeyguardBypassController = keyguardBypassController;
mHeadsUpManager = headsUpManager;
mStatusBarStateController = statusBarStateController;
@@ -64,14 +64,14 @@
if (inPinnedMode) {
mNotificationShadeWindowController.setHeadsUpShowing(true);
mStatusBarWindowController.setForceStatusBarVisible(true);
- if (mNotificationPanelViewController.isFullyCollapsed()) {
- mNotificationPanelViewController.updateTouchableRegion();
+ if (mShadeViewController.isFullyCollapsed()) {
+ mShadeViewController.updateTouchableRegion();
}
} else {
boolean bypassKeyguard = mKeyguardBypassController.getBypassEnabled()
&& mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
- if (!mNotificationPanelViewController.isFullyCollapsed()
- || mNotificationPanelViewController.isTracking()
+ if (!mShadeViewController.isFullyCollapsed()
+ || mShadeViewController.isTracking()
|| bypassKeyguard) {
// We are currently tracking or is open and the shade doesn't need to
//be kept
@@ -85,7 +85,7 @@
//animation
// is finished.
mHeadsUpManager.setHeadsUpGoingAway(true);
- mNotificationPanelViewController.getNotificationStackScrollLayoutController()
+ mShadeViewController.getNotificationStackScrollLayoutController()
.runAfterAnimationFinished(() -> {
if (!mHeadsUpManager.hasPinnedHeadsUp()) {
mNotificationShadeWindowController.setHeadsUpShowing(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 70aab61..f7646d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -69,11 +69,11 @@
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.navigationbar.TaskbarDelegate;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shade.ShadeExpansionListener;
import com.android.systemui.shade.ShadeExpansionStateManager;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -251,7 +251,7 @@
protected LockPatternUtils mLockPatternUtils;
protected ViewMediatorCallback mViewMediatorCallback;
@Nullable protected CentralSurfaces mCentralSurfaces;
- private NotificationPanelViewController mNotificationPanelViewController;
+ private ShadeViewController mShadeViewController;
private BiometricUnlockController mBiometricUnlockController;
private boolean mCentralSurfacesRegistered;
@@ -371,7 +371,7 @@
@Override
public void registerCentralSurfaces(CentralSurfaces centralSurfaces,
- NotificationPanelViewController notificationPanelViewController,
+ ShadeViewController shadeViewController,
ShadeExpansionStateManager shadeExpansionStateManager,
BiometricUnlockController biometricUnlockController,
View notificationContainer,
@@ -380,7 +380,7 @@
mBiometricUnlockController = biometricUnlockController;
mPrimaryBouncerCallbackInteractor.addBouncerExpansionCallback(mExpansionCallback);
- mNotificationPanelViewController = notificationPanelViewController;
+ mShadeViewController = shadeViewController;
if (shadeExpansionStateManager != null) {
shadeExpansionStateManager.addExpansionListener(this);
}
@@ -482,8 +482,8 @@
// Avoid having the shade and the bouncer open at the same time over a dream.
final boolean hideBouncerOverDream =
mDreamOverlayStateController.isOverlayActive()
- && (mNotificationPanelViewController.isExpanded()
- || mNotificationPanelViewController.isExpanding());
+ && (mShadeViewController.isExpanded()
+ || mShadeViewController.isExpanding());
final boolean isUserTrackingStarted =
event.getFraction() != EXPANSION_HIDDEN && event.getTracking();
@@ -495,7 +495,7 @@
&& !mKeyguardStateController.isOccluded()
&& !mKeyguardStateController.canDismissLockScreen()
&& !bouncerIsAnimatingAway()
- && !mNotificationPanelViewController.isUnlockHintRunning()
+ && !mShadeViewController.isUnlockHintRunning()
&& !(mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED);
}
@@ -699,7 +699,7 @@
if (mKeyguardStateController.isShowing()) {
final boolean isOccluded = mKeyguardStateController.isOccluded();
// Hide quick settings.
- mNotificationPanelViewController.resetViews(/* animate= */ !isOccluded);
+ mShadeViewController.resetViews(/* animate= */ !isOccluded);
// Hide bouncer and quick-quick settings.
if (isOccluded && !mDozing) {
mCentralSurfaces.hideKeyguard();
@@ -862,7 +862,7 @@
public void startPreHideAnimation(Runnable finishRunnable) {
if (primaryBouncerIsShowing()) {
mPrimaryBouncerInteractor.startDisappearAnimation(finishRunnable);
- mNotificationPanelViewController.startBouncerPreHideAnimation();
+ mShadeViewController.startBouncerPreHideAnimation();
// We update the state (which will show the keyguard) only if an animation will run on
// the keyguard. If there is no animation, we wait before updating the state so that we
@@ -873,12 +873,12 @@
} else if (finishRunnable != null) {
finishRunnable.run();
}
- mNotificationPanelViewController.blockExpansionForCurrentTouch();
+ mShadeViewController.blockExpansionForCurrentTouch();
}
@Override
public void blockPanelExpansionFromCurrentTouch() {
- mNotificationPanelViewController.blockExpansionForCurrentTouch();
+ mShadeViewController.blockExpansionForCurrentTouch();
}
@Override
@@ -975,7 +975,7 @@
public void onKeyguardFadedAway() {
mNotificationContainer.postDelayed(() -> mNotificationShadeWindowController
.setKeyguardFadingAway(false), 100);
- mNotificationPanelViewController.resetViewGroupFade();
+ mShadeViewController.resetViewGroupFade();
mCentralSurfaces.finishKeyguardFadingAway();
mBiometricUnlockController.finishKeyguardFadingAway();
WindowManagerGlobal.getInstance().trimMemory(
@@ -1050,7 +1050,7 @@
if (hideImmediately) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
} else {
- mNotificationPanelViewController.expandToNotifications();
+ mShadeViewController.expandToNotifications();
}
}
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
index b1642d6..9f69db9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
@@ -21,7 +21,7 @@
override fun onIntentStarted(willAnimate: Boolean) {
delegate.onIntentStarted(willAnimate)
if (willAnimate) {
- centralSurfaces.notificationPanelViewController.setIsLaunchAnimationRunning(true)
+ centralSurfaces.shadeViewController.setIsLaunchAnimationRunning(true)
} else {
centralSurfaces.collapsePanelOnMainThread()
}
@@ -29,16 +29,16 @@
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
delegate.onLaunchAnimationStart(isExpandingFullyAbove)
- centralSurfaces.notificationPanelViewController.setIsLaunchAnimationRunning(true)
+ centralSurfaces.shadeViewController.setIsLaunchAnimationRunning(true)
if (!isExpandingFullyAbove) {
- centralSurfaces.notificationPanelViewController.collapseWithDuration(
+ centralSurfaces.shadeViewController.collapseWithDuration(
ActivityLaunchAnimator.TIMINGS.totalDuration.toInt())
}
}
override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
delegate.onLaunchAnimationEnd(isExpandingFullyAbove)
- centralSurfaces.notificationPanelViewController.setIsLaunchAnimationRunning(false)
+ centralSurfaces.shadeViewController.setIsLaunchAnimationRunning(false)
centralSurfaces.onLaunchAnimationEnd(isExpandingFullyAbove)
}
@@ -48,12 +48,12 @@
linearProgress: Float
) {
delegate.onLaunchAnimationProgress(state, progress, linearProgress)
- centralSurfaces.notificationPanelViewController.applyLaunchAnimationProgress(linearProgress)
+ centralSurfaces.shadeViewController.applyLaunchAnimationProgress(linearProgress)
}
override fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean?) {
delegate.onLaunchAnimationCancelled()
- centralSurfaces.notificationPanelViewController.setIsLaunchAnimationRunning(false)
+ centralSurfaces.shadeViewController.setIsLaunchAnimationRunning(false)
centralSurfaces.onLaunchAnimationCancelled(isLaunchForActivity)
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index c623201..bd5815aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -55,11 +55,10 @@
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.NotificationClickNotifier;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -122,7 +121,7 @@
private final CentralSurfaces mCentralSurfaces;
private final NotificationPresenter mPresenter;
- private final NotificationPanelViewController mNotificationPanel;
+ private final ShadeViewController mNotificationPanel;
private final ActivityLaunchAnimator mActivityLaunchAnimator;
private final NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
private final UserTracker mUserTracker;
@@ -157,7 +156,7 @@
OnUserInteractionCallback onUserInteractionCallback,
CentralSurfaces centralSurfaces,
NotificationPresenter presenter,
- NotificationPanelViewController panel,
+ ShadeViewController panel,
ActivityLaunchAnimator activityLaunchAnimator,
NotificationLaunchAnimatorControllerProvider notificationAnimationProvider,
LaunchFullScreenIntentProvider launchFullScreenIntentProvider,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 39362cf..dfaee4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -31,15 +31,14 @@
import android.view.View;
import android.view.accessibility.AccessibilityManager;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.QuickSettingsController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -58,14 +57,12 @@
import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -84,9 +81,8 @@
private final NotifShadeEventSource mNotifShadeEventSource;
private final NotificationMediaManager mMediaManager;
private final NotificationGutsManager mGutsManager;
- private final LockscreenGestureLogger mLockscreenGestureLogger;
- private final NotificationPanelViewController mNotificationPanel;
+ private final ShadeViewController mNotificationPanel;
private final HeadsUpManagerPhone mHeadsUpManager;
private final AboveShelfObserver mAboveShelfObserver;
private final DozeScrimController mDozeScrimController;
@@ -109,7 +105,7 @@
@Inject
StatusBarNotificationPresenter(
Context context,
- NotificationPanelViewController panel,
+ ShadeViewController panel,
QuickSettingsController quickSettingsController,
HeadsUpManagerPhone headsUp,
NotificationShadeWindowView statusBarWindow,
@@ -151,7 +147,6 @@
mNotifShadeEventSource = notifShadeEventSource;
mMediaManager = notificationMediaManager;
mGutsManager = notificationGutsManager;
- mLockscreenGestureLogger = lockscreenGestureLogger;
mAboveShelfObserver = new AboveShelfObserver(stackScrollerController.getView());
mNotificationShadeWindowController = notificationShadeWindowController;
mNotifPipelineFlags = notifPipelineFlags;
@@ -239,34 +234,6 @@
}
@Override
- public void onActivated(ActivatableNotificationView view) {
- onActivated();
- if (view != null) {
- mNotificationPanel.getShadeNotificationPresenter().setActivatedChild(view);
- }
- }
-
- public void onActivated() {
- mLockscreenGestureLogger.write(
- MetricsEvent.ACTION_LS_NOTE,
- 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
- mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_NOTIFICATION_FALSE_TOUCH);
- ActivatableNotificationView previousView =
- mNotificationPanel.getShadeNotificationPresenter().getActivatedChild();
- if (previousView != null) {
- previousView.makeInactive(true /* animate */);
- }
- }
-
- @Override
- public void onActivationReset(ActivatableNotificationView view) {
- if (view == mNotificationPanel.getShadeNotificationPresenter().getActivatedChild()) {
- mNotificationPanel.getShadeNotificationPresenter().setActivatedChild(null);
- mKeyguardIndicationController.hideTransientIndication();
- }
- }
-
- @Override
public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
mMediaManager.updateMediaMetaData(metaDataChanged, allowEnterAnimation);
}
@@ -276,7 +243,7 @@
boolean nowExpanded) {
mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
mCentralSurfaces.wakeUpIfDozing(
- SystemClock.uptimeMillis(), clickedView, "NOTIFICATION_CLICK",
+ SystemClock.uptimeMillis(), "NOTIFICATION_CLICK",
PowerManager.WAKE_REASON_GESTURE);
if (nowExpanded) {
if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
@@ -364,26 +331,6 @@
return true;
}
- if (sbn.getNotification().fullScreenIntent != null
- && !mNotifPipelineFlags.fullScreenIntentRequiresKeyguard()) {
- // we don't allow head-up on the lockscreen (unless there's a
- // "showWhenLocked" activity currently showing) if
- // the potential HUN has a fullscreen intent
- if (mKeyguardStateController.isShowing() && !mCentralSurfaces.isOccluded()) {
- if (DEBUG) {
- Log.d(TAG, "No heads up: entry has fullscreen intent on lockscreen "
- + sbn.getKey());
- }
- return true;
- }
-
- if (mAccessibilityManager.isTouchExplorationEnabled()) {
- if (DEBUG) {
- Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
- }
- return true;
- }
- }
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 0cd3401..8fa803e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -277,7 +277,7 @@
// Show AOD. That'll cause the KeyguardVisibilityHelper to call
// #animateInKeyguard.
- mCentralSurfaces.notificationPanelViewController.showAodUi()
+ mCentralSurfaces.shadeViewController.showAodUi()
}
}, (ANIMATE_IN_KEYGUARD_DELAY * animatorDurationScale).toLong())
@@ -326,7 +326,7 @@
// already expanded and showing notifications/QS, the animation looks really messy. For now,
// disable it if the notification panel is expanded.
if ((!this::mCentralSurfaces.isInitialized ||
- mCentralSurfaces.notificationPanelViewController.isPanelExpanded) &&
+ mCentralSurfaces.shadeViewController.isPanelExpanded) &&
// Status bar might be expanded because we have started
// playing the animation already
!isAnimationPlaying()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 5d4adda..015ee7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -44,6 +44,7 @@
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.NotificationsQuickSettingsContainer;
import com.android.systemui.shade.ShadeExpansionStateManager;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.LegacyNotificationShelfControllerImpl;
import com.android.systemui.statusbar.NotificationShelf;
@@ -52,6 +53,7 @@
import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModelModule;
import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinderWrapperControllerImpl;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
@@ -76,17 +78,18 @@
import com.android.systemui.util.CarrierConfigTracker;
import com.android.systemui.util.settings.SecureSettings;
-import java.util.concurrent.Executor;
-
-import javax.inject.Named;
-import javax.inject.Provider;
-
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoSet;
-@Module(subcomponents = StatusBarFragmentComponent.class)
+import java.util.concurrent.Executor;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+
+@Module(subcomponents = StatusBarFragmentComponent.class,
+ includes = { ActivatableNotificationViewModelModule.class })
public abstract class StatusBarViewModule {
public static final String SHADE_HEADER = "large_screen_shade_header";
@@ -163,6 +166,12 @@
}
/** */
+ @Binds
+ @CentralSurfacesComponent.CentralSurfacesScope
+ abstract ShadeViewController bindsShadeViewController(
+ NotificationPanelViewController notificationPanelViewController);
+
+ /** */
@Provides
@CentralSurfacesComponent.CentralSurfacesScope
public static LockIconView getLockIconView(
@@ -301,7 +310,7 @@
StatusBarIconController.DarkIconManager.Factory darkIconManagerFactory,
StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
KeyguardStateController keyguardStateController,
- NotificationPanelViewController notificationPanelViewController,
+ ShadeViewController shadeViewController,
StatusBarStateController statusBarStateController,
CommandQueue commandQueue,
CarrierConfigTracker carrierConfigTracker,
@@ -324,7 +333,7 @@
darkIconManagerFactory,
statusBarHideIconsForBouncerManager,
keyguardStateController,
- notificationPanelViewController,
+ shadeViewController,
statusBarStateController,
commandQueue,
carrierConfigTracker,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index fe63994..453dd1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -52,8 +52,8 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeExpansionStateManager;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.OperatorNameView;
import com.android.systemui.statusbar.OperatorNameViewController;
@@ -107,7 +107,7 @@
private PhoneStatusBarView mStatusBar;
private final StatusBarStateController mStatusBarStateController;
private final KeyguardStateController mKeyguardStateController;
- private final NotificationPanelViewController mNotificationPanelViewController;
+ private final ShadeViewController mShadeViewController;
private LinearLayout mEndSideContent;
private View mClockView;
private View mOngoingCallChip;
@@ -198,7 +198,7 @@
StatusBarIconController.DarkIconManager.Factory darkIconManagerFactory,
StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
KeyguardStateController keyguardStateController,
- NotificationPanelViewController notificationPanelViewController,
+ ShadeViewController shadeViewController,
StatusBarStateController statusBarStateController,
CommandQueue commandQueue,
CarrierConfigTracker carrierConfigTracker,
@@ -221,7 +221,7 @@
mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager;
mDarkIconManagerFactory = darkIconManagerFactory;
mKeyguardStateController = keyguardStateController;
- mNotificationPanelViewController = notificationPanelViewController;
+ mShadeViewController = shadeViewController;
mStatusBarStateController = statusBarStateController;
mCommandQueue = commandQueue;
mCarrierConfigTracker = carrierConfigTracker;
@@ -509,7 +509,7 @@
private boolean shouldHideNotificationIcons() {
if (!mShadeExpansionStateManager.isClosed()
- && mNotificationPanelViewController.shouldHideStatusBarIconsWhenExpanded()) {
+ && mShadeViewController.shouldHideStatusBarIconsWhenExpanded()) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index a4cb99b..6186c43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -28,8 +28,8 @@
import com.android.systemui.R;
import com.android.systemui.settings.brightness.BrightnessSliderController;
import com.android.systemui.settings.brightness.ToggleSlider;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowView;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import java.util.Objects;
@@ -43,7 +43,7 @@
private final NotificationShadeWindowView mStatusBarWindow;
private final Consumer<Boolean> mVisibilityCallback;
- private final NotificationPanelViewController mNotificationPanel;
+ private final ShadeViewController mNotificationPanel;
private final NotificationShadeDepthController mDepthController;
private final ArraySet<BrightnessMirrorListener> mBrightnessMirrorListeners = new ArraySet<>();
private final BrightnessSliderController.Factory mToggleSliderFactory;
@@ -54,7 +54,7 @@
private int mLastBrightnessSliderWidth = -1;
public BrightnessMirrorController(NotificationShadeWindowView statusBarWindow,
- NotificationPanelViewController notificationPanelViewController,
+ ShadeViewController shadeViewController,
NotificationShadeDepthController notificationShadeDepthController,
BrightnessSliderController.Factory factory,
@NonNull Consumer<Boolean> visibilityCallback) {
@@ -62,7 +62,7 @@
mToggleSliderFactory = factory;
mBrightnessMirror = statusBarWindow.findViewById(R.id.brightness_mirror_container);
mToggleSliderController = setMirrorLayout();
- mNotificationPanel = notificationPanelViewController;
+ mNotificationPanel = shadeViewController;
mDepthController = notificationShadeDepthController;
mNotificationPanel.setAlphaChangeAnimationEndAction(() -> {
mBrightnessMirror.setVisibility(View.INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index a08aa88..403a7e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -21,7 +21,6 @@
import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_STANDARD;
import android.app.ActivityManager;
-import android.app.Notification;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
@@ -135,7 +134,6 @@
@Nullable
private RevealParams mRevealParams;
private Rect mContentBackgroundBounds;
- private boolean mIsFocusAnimationFlagActive;
private boolean mIsAnimatingAppearance = false;
// TODO(b/193539698): move these to a Controller
@@ -433,7 +431,7 @@
// case to prevent flicker.
if (!mRemoved) {
ViewGroup parent = (ViewGroup) getParent();
- if (animate && parent != null && mIsFocusAnimationFlagActive) {
+ if (animate && parent != null) {
ViewGroup grandParent = (ViewGroup) parent.getParent();
ViewGroupOverlay overlay = parent.getOverlay();
@@ -598,24 +596,10 @@
}
/**
- * Sets whether the feature flag for the revised inline reply animation is active or not.
- * @param active
- */
- public void setIsFocusAnimationFlagActive(boolean active) {
- mIsFocusAnimationFlagActive = active;
- }
-
- /**
* Focuses the RemoteInputView and animates its appearance
*/
public void focusAnimated() {
- if (!mIsFocusAnimationFlagActive && getVisibility() != VISIBLE
- && mRevealParams != null) {
- android.animation.Animator animator = mRevealParams.createCircularRevealAnimator(this);
- animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- animator.start();
- } else if (mIsFocusAnimationFlagActive && getVisibility() != VISIBLE) {
+ if (getVisibility() != VISIBLE) {
mIsAnimatingAppearance = true;
setAlpha(0f);
Animator focusAnimator = getFocusAnimator(getActionsContainerLayout());
@@ -670,37 +654,19 @@
}
private void reset() {
- if (mIsFocusAnimationFlagActive) {
- mProgressBar.setVisibility(INVISIBLE);
- mResetting = true;
- mSending = false;
- onDefocus(true /* animate */, false /* logClose */, () -> {
- mEntry.remoteInputTextWhenReset = SpannedString.valueOf(mEditText.getText());
- mEditText.getText().clear();
- mEditText.setEnabled(isAggregatedVisible());
- mSendButton.setVisibility(VISIBLE);
- mController.removeSpinning(mEntry.getKey(), mToken);
- updateSendButton();
- setAttachment(null);
- mResetting = false;
- });
- return;
- }
-
+ mProgressBar.setVisibility(INVISIBLE);
mResetting = true;
mSending = false;
- mEntry.remoteInputTextWhenReset = SpannedString.valueOf(mEditText.getText());
-
- mEditText.getText().clear();
- mEditText.setEnabled(isAggregatedVisible());
- mSendButton.setVisibility(VISIBLE);
- mProgressBar.setVisibility(INVISIBLE);
- mController.removeSpinning(mEntry.getKey(), mToken);
- updateSendButton();
- onDefocus(false /* animate */, false /* logClose */, null /* doAfterDefocus */);
- setAttachment(null);
-
- mResetting = false;
+ onDefocus(true /* animate */, false /* logClose */, () -> {
+ mEntry.remoteInputTextWhenReset = SpannedString.valueOf(mEditText.getText());
+ mEditText.getText().clear();
+ mEditText.setEnabled(isAggregatedVisible());
+ mSendButton.setVisibility(VISIBLE);
+ mController.removeSpinning(mEntry.getKey(), mToken);
+ updateSendButton();
+ setAttachment(null);
+ mResetting = false;
+ });
}
@Override
@@ -844,7 +810,7 @@
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
- if (mIsFocusAnimationFlagActive) setPivotY(getMeasuredHeight());
+ setPivotY(getMeasuredHeight());
if (mContentBackgroundBounds != null) {
mContentBackground.setBounds(mContentBackgroundBounds);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
index 22b4c9d..e9b1d54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
@@ -30,8 +30,6 @@
import android.view.View
import com.android.internal.logging.UiEventLogger
import com.android.systemui.R
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags.NOTIFICATION_INLINE_REPLY_ANIMATION
import com.android.systemui.statusbar.NotificationRemoteInputManager
import com.android.systemui.statusbar.RemoteInputController
import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -63,8 +61,6 @@
var revealParams: RevealParams?
- val isFocusAnimationFlagActive: Boolean
-
/**
* Sets the smart reply that should be inserted in the remote input, or `null` if the user is
* not editing a smart reply.
@@ -122,7 +118,6 @@
private val remoteInputController: RemoteInputController,
private val shortcutManager: ShortcutManager,
private val uiEventLogger: UiEventLogger,
- private val mFlags: FeatureFlags
) : RemoteInputViewController {
private val onSendListeners = ArraySet<OnSendRemoteInputListener>()
@@ -154,9 +149,6 @@
override val isActive: Boolean get() = view.isActive
- override val isFocusAnimationFlagActive: Boolean
- get() = mFlags.isEnabled(NOTIFICATION_INLINE_REPLY_ANIMATION)
-
override fun bind() {
if (isBound) return
isBound = true
@@ -167,7 +159,6 @@
view.setSupportedMimeTypes(it.allowedDataTypes)
}
view.setRevealParameters(revealParams)
- view.setIsFocusAnimationFlagActive(isFocusAnimationFlagActive)
view.addOnEditTextFocusChangedListener(onFocusChangeListener)
view.addOnSendRemoteInputListener(onSendRemoteInputListener)
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
index 3805019..412b315 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusManager.kt
@@ -353,6 +353,8 @@
// before CoreStartables run, and will not be removed.
// In many cases, it reports the battery level of the stylus.
registerBatteryListener(deviceId)
+ } else if (device.bluetoothAddress != null) {
+ onStylusBluetoothConnected(deviceId, device.bluetoothAddress)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
index d1bd73a..d74906a 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
@@ -39,11 +39,11 @@
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.settings.GlobalSettings
import dagger.Lazy
-import java.util.function.Consumer
-import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
+import java.util.function.Consumer
+import javax.inject.Inject
/**
* Controls folding to AOD animation: when AOD is enabled and foldable device is folded we play a
@@ -128,7 +128,7 @@
}
private fun getShadeFoldAnimator(): ShadeFoldAnimator =
- centralSurfaces.notificationPanelViewController.shadeFoldAnimator
+ centralSurfaces.shadeViewController.shadeFoldAnimator
private fun setAnimationState(playing: Boolean) {
shouldPlayAnimation = playing
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index aa26e68..77210b7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -2344,7 +2344,7 @@
}
@VisibleForTesting
- void clearInternalHandleAfterTest() {
+ void clearInternalHandlerAfterTest() {
if (mHandler != null) {
mHandler.removeCallbacksAndMessages(null);
}
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/accessibility/data/repository/AccessibilityRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/data/repository/AccessibilityRepositoryTest.kt
new file mode 100644
index 0000000..aff52f5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/data/repository/AccessibilityRepositoryTest.kt
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.accessibility.data.repository
+
+import android.testing.AndroidTestingRunner
+import android.view.accessibility.AccessibilityManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class AccessibilityRepositoryTest : SysuiTestCase() {
+
+ @Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ // mocks
+ @Mock private lateinit var a11yManager: AccessibilityManager
+
+ // real impls
+ private val underTest by lazy { AccessibilityRepository(a11yManager) }
+
+ @Test
+ fun isTouchExplorationEnabled_reflectsA11yManager_initFalse() = runTest {
+ whenever(a11yManager.isTouchExplorationEnabled).thenReturn(false)
+ val isTouchExplorationEnabled by collectLastValue(underTest.isTouchExplorationEnabled)
+ assertThat(isTouchExplorationEnabled).isFalse()
+ }
+
+ @Test
+ fun isTouchExplorationEnabled_reflectsA11yManager_initTrue() = runTest {
+ whenever(a11yManager.isTouchExplorationEnabled).thenReturn(true)
+ val isTouchExplorationEnabled by collectLastValue(underTest.isTouchExplorationEnabled)
+ assertThat(isTouchExplorationEnabled).isTrue()
+ }
+
+ @Test
+ fun isTouchExplorationEnabled_reflectsA11yManager_changeTrue() = runTest {
+ whenever(a11yManager.isTouchExplorationEnabled).thenReturn(false)
+ val isTouchExplorationEnabled by collectLastValue(underTest.isTouchExplorationEnabled)
+ runCurrent()
+ withArgCaptor { verify(a11yManager).addTouchExplorationStateChangeListener(capture()) }
+ .onTouchExplorationStateChanged(/* enabled = */ true)
+ assertThat(isTouchExplorationEnabled).isTrue()
+ }
+
+ @Test
+ fun isTouchExplorationEnabled_reflectsA11yManager_changeFalse() = runTest {
+ whenever(a11yManager.isTouchExplorationEnabled).thenReturn(true)
+ val isTouchExplorationEnabled by collectLastValue(underTest.isTouchExplorationEnabled)
+ runCurrent()
+ withArgCaptor { verify(a11yManager).addTouchExplorationStateChangeListener(capture()) }
+ .onTouchExplorationStateChanged(/* enabled = */ false)
+ assertThat(isTouchExplorationEnabled).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt
index dd87f6e..f4dacab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt
@@ -18,6 +18,8 @@
import android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE
import android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT
+import android.hardware.biometrics.BiometricConstants
+import android.hardware.face.FaceManager
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import android.view.View
@@ -34,6 +36,7 @@
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
+import org.mockito.Mockito.times
import org.mockito.junit.MockitoJUnit
@@ -98,7 +101,7 @@
}
@Test
- fun ignoresFaceErrors() {
+ fun ignoresFaceErrors_faceIsNotClass3_notLockoutError() {
biometricView.onDialogAnimatedIn()
biometricView.onError(TYPE_FACE, "not a face")
waitForIdleSync()
@@ -113,5 +116,47 @@
verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
}
+ @Test
+ fun doNotIgnoresFaceErrors_faceIsClass3_notLockoutError() {
+ biometricView.isFaceClass3 = true
+ biometricView.onDialogAnimatedIn()
+ biometricView.onError(TYPE_FACE, "not a face")
+ waitForIdleSync()
+
+ assertThat(biometricView.isAuthenticating).isTrue()
+ verify(callback, never()).onAction(AuthBiometricView.Callback.ACTION_ERROR)
+
+ biometricView.onError(TYPE_FINGERPRINT, "that's a nope")
+ TestableLooper.get(this).moveTimeForward(1000)
+ waitForIdleSync()
+
+ verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
+ }
+
+ @Test
+ fun doNotIgnoresFaceErrors_faceIsClass3_lockoutError() {
+ biometricView.isFaceClass3 = true
+ biometricView.onDialogAnimatedIn()
+ biometricView.onError(
+ TYPE_FACE,
+ FaceManager.getErrorString(
+ biometricView.context,
+ BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT,
+ 0 /*vendorCode */
+ )
+ )
+ waitForIdleSync()
+
+ assertThat(biometricView.isAuthenticating).isTrue()
+ verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
+
+ biometricView.onError(TYPE_FINGERPRINT, "that's a nope")
+ TestableLooper.get(this).moveTimeForward(1000)
+ waitForIdleSync()
+
+ verify(callback, times(2)).onAction(AuthBiometricView.Callback.ACTION_ERROR)
+ }
+
+
override fun waitForIdleSync() = TestableLooper.get(this).processAllMessages()
}
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/dreams/touch/ShadeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java
index 5704ef3..872c079 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java
@@ -28,7 +28,7 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.statusbar.phone.CentralSurfaces;
@@ -49,7 +49,7 @@
CentralSurfaces mCentralSurfaces;
@Mock
- NotificationPanelViewController mNotificationPanelViewController;
+ ShadeViewController mShadeViewController;
@Mock
DreamTouchHandler.TouchSession mTouchSession;
@@ -63,8 +63,8 @@
MockitoAnnotations.initMocks(this);
mTouchHandler = new ShadeTouchHandler(Optional.of(mCentralSurfaces),
TOUCH_HEIGHT);
- when(mCentralSurfaces.getNotificationPanelViewController())
- .thenReturn(mNotificationPanelViewController);
+ when(mCentralSurfaces.getShadeViewController())
+ .thenReturn(mShadeViewController);
}
/**
@@ -97,7 +97,7 @@
}
/**
- * Ensure touches are propagated to the {@link NotificationPanelViewController}.
+ * Ensure touches are propagated to the {@link ShadeViewController}.
*/
@Test
public void testEventPropagation() {
@@ -110,7 +110,7 @@
mTouchHandler.onSessionStart(mTouchSession);
verify(mTouchSession).registerInputListener(inputEventListenerArgumentCaptor.capture());
inputEventListenerArgumentCaptor.getValue().onInputEvent(motionEvent);
- verify(mNotificationPanelViewController).handleExternalTouch(motionEvent);
+ verify(mShadeViewController).handleExternalTouch(motionEvent);
}
}
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/BiometricSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
index 5d83f56..726728a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
@@ -227,10 +227,14 @@
assertThat(faceEnrolled()).isFalse()
+ whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true)
+
enrollmentChange(FACE, ANOTHER_USER_ID, true)
assertThat(faceEnrolled()).isFalse()
+ whenever(authController.isFaceAuthEnrolled(PRIMARY_USER_ID)).thenReturn(true)
+
enrollmentChange(FACE, PRIMARY_USER_ID, true)
assertThat(faceEnrolled()).isTrue()
@@ -264,6 +268,7 @@
verify(authController).addCallback(authControllerCallback.capture())
+ whenever(authController.isFaceAuthEnrolled(ANOTHER_USER_ID)).thenReturn(true)
enrollmentChange(FACE, ANOTHER_USER_ID, true)
assertThat(faceEnrolled()).isTrue()
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/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/media/controls/models/player/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/SeekBarViewModelTest.kt
index 56c91bc..e3c8b05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/SeekBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/SeekBarViewModelTest.kt
@@ -22,6 +22,7 @@
import android.media.session.PlaybackState
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import android.view.MotionEvent
import android.widget.SeekBar
import androidx.arch.core.executor.ArchTaskExecutor
import androidx.arch.core.executor.TaskExecutor
@@ -466,21 +467,63 @@
whenever(mockController.getTransportControls()).thenReturn(mockTransport)
whenever(falsingManager.isFalseTouch(Classifier.MEDIA_SEEKBAR)).thenReturn(true)
whenever(falsingManager.isFalseTap(anyInt())).thenReturn(true)
- viewModel.updateController(mockController)
- val pos = 169
- viewModel.attachTouchHandlers(mockBar)
+ viewModel.updateController(mockController)
+ val pos = 40
+ val bar = SeekBar(context).apply { progress = pos }
with(viewModel.seekBarListener) {
- onStartTrackingTouch(mockBar)
- onProgressChanged(mockBar, pos, true)
- onStopTrackingTouch(mockBar)
+ onStartTrackingTouch(bar)
+ onStopTrackingTouch(bar)
}
+ fakeExecutor.runAllReady()
// THEN transport controls should not be used
verify(mockTransport, never()).seekTo(pos.toLong())
}
@Test
+ fun onSeekbarGrabInvalidTouch() {
+ whenever(mockController.getTransportControls()).thenReturn(mockTransport)
+ viewModel.firstMotionEvent =
+ MotionEvent.obtain(12L, 13L, MotionEvent.ACTION_DOWN, 76F, 0F, 0)
+ viewModel.lastMotionEvent = MotionEvent.obtain(12L, 14L, MotionEvent.ACTION_UP, 78F, 4F, 0)
+ val pos = 78
+
+ viewModel.updateController(mockController)
+ // WHEN user ends drag
+ val bar = SeekBar(context).apply { progress = pos }
+ with(viewModel.seekBarListener) {
+ onStartTrackingTouch(bar)
+ onStopTrackingTouch(bar)
+ }
+ fakeExecutor.runAllReady()
+
+ // THEN transport controls should not be used
+ verify(mockTransport, never()).seekTo(pos.toLong())
+ }
+
+ @Test
+ fun onSeekbarGrabValidTouch() {
+ whenever(mockController.transportControls).thenReturn(mockTransport)
+ viewModel.firstMotionEvent =
+ MotionEvent.obtain(12L, 13L, MotionEvent.ACTION_DOWN, 36F, 0F, 0)
+ viewModel.lastMotionEvent = MotionEvent.obtain(12L, 14L, MotionEvent.ACTION_UP, 40F, 1F, 0)
+ val pos = 40
+
+ viewModel.updateController(mockController)
+ // WHEN user ends drag
+ val bar = SeekBar(context).apply { progress = pos }
+ with(viewModel.seekBarListener) {
+ onStartTrackingTouch(bar)
+ onStopTrackingTouch(bar)
+ }
+ fakeExecutor.runAllReady()
+
+ // THEN transport controls should be used
+ verify(mockTransport).seekTo(pos.toLong())
+ }
+
+ @Test
fun queuePollTaskWhenPlaying() {
// GIVEN that the track is playing
val state =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt
index 4565762..c9956f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt
@@ -24,6 +24,8 @@
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.media.controls.models.player.MediaViewHolder
+import com.android.systemui.media.controls.models.recommendation.RecommendationViewHolder
import com.android.systemui.media.controls.util.MediaFlags
import com.android.systemui.util.animation.MeasurementInput
import com.android.systemui.util.animation.TransitionLayout
@@ -55,13 +57,12 @@
@Mock private lateinit var mockCopiedState: TransitionViewState
@Mock private lateinit var detailWidgetState: WidgetState
@Mock private lateinit var controlWidgetState: WidgetState
- @Mock private lateinit var bgWidgetState: WidgetState
@Mock private lateinit var mediaTitleWidgetState: WidgetState
@Mock private lateinit var mediaSubTitleWidgetState: WidgetState
@Mock private lateinit var mediaContainerWidgetState: WidgetState
@Mock private lateinit var mediaFlags: MediaFlags
- val delta = 0.1F
+ private val delta = 0.1F
private lateinit var mediaViewController: MediaViewController
@@ -84,13 +85,13 @@
mediaViewController.attach(player, MediaViewController.TYPE.PLAYER)
// Change the height to see the effect of orientation change.
- MediaViewController.backgroundIds.forEach { id ->
+ MediaViewHolder.backgroundIds.forEach { id ->
mediaViewController.expandedLayout.getConstraint(id).layout.mHeight = 10
}
newConfig.orientation = ORIENTATION_LANDSCAPE
configurationController.onConfigurationChanged(newConfig)
- MediaViewController.backgroundIds.forEach { id ->
+ MediaViewHolder.backgroundIds.forEach { id ->
assertTrue(
mediaViewController.expandedLayout.getConstraint(id).layout.mHeight ==
context.resources.getDimensionPixelSize(
@@ -107,7 +108,7 @@
mediaViewController.attach(recommendation, MediaViewController.TYPE.RECOMMENDATION)
// Change the height to see the effect of orientation change.
mediaViewController.expandedLayout
- .getConstraint(MediaViewController.recSizingViewId)
+ .getConstraint(RecommendationViewHolder.backgroundId)
.layout
.mHeight = 10
newConfig.orientation = ORIENTATION_LANDSCAPE
@@ -115,7 +116,7 @@
assertTrue(
mediaViewController.expandedLayout
- .getConstraint(MediaViewController.recSizingViewId)
+ .getConstraint(RecommendationViewHolder.backgroundId)
.layout
.mHeight ==
context.resources.getDimensionPixelSize(R.dimen.qs_media_session_height_expanded)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index c3fabfe..21a7a34 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -39,7 +39,7 @@
import android.util.FeatureFlagUtils;
import android.view.View;
-import androidx.test.filters.SmallTest;
+import androidx.test.filters.MediumTest;
import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
@@ -65,7 +65,7 @@
import java.util.List;
import java.util.Optional;
-@SmallTest
+@MediumTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class MediaOutputDialogTest extends SysuiTestCase {
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 22a5b21..7dc622b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
@@ -36,6 +36,7 @@
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.content.pm.UserInfo
+import android.graphics.drawable.Icon
import android.os.UserHandle
import android.os.UserManager
import androidx.test.ext.truth.content.IntentSubject.assertThat
@@ -64,7 +65,6 @@
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.doNothing
-import org.mockito.Mockito.isNull
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
@@ -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()
@@ -326,7 +327,8 @@
entryPoint = expectedInfo.entryPoint!!,
)
- verifyZeroInteractions(context)
+ // Context package name used to create bubble icon from drawable resource id
+ verify(context).packageName
verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle)
verifyZeroInteractions(eventLogger)
}
@@ -343,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()
@@ -383,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(
@@ -603,14 +605,19 @@
private fun verifyNoteTaskOpenInBubbleInUser(userHandle: UserHandle) {
val intentCaptor = argumentCaptor<Intent>()
+ val iconCaptor = argumentCaptor<Icon>()
verify(bubbles)
- .showOrHideAppBubble(capture(intentCaptor), eq(userHandle), /* icon = */ isNull())
+ .showOrHideAppBubble(capture(intentCaptor), eq(userHandle), capture(iconCaptor))
intentCaptor.value.let { intent ->
assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE)
assertThat(intent.`package`).isEqualTo(NOTE_TASK_PACKAGE_NAME)
assertThat(intent.flags).isEqualTo(FLAG_ACTIVITY_NEW_TASK)
assertThat(intent.getBooleanExtra(Intent.EXTRA_USE_STYLUS_MODE, false)).isTrue()
}
+ iconCaptor.value.let { icon ->
+ assertThat(icon).isNotNull()
+ assertThat(icon.resId).isEqualTo(R.drawable.ic_note_task_shortcut_widget)
+ }
}
// region updateNoteTaskAsUser
@@ -711,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/PulsingGestureListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
index 76aa08a..d7c06a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
@@ -17,11 +17,11 @@
package com.android.systemui.shade
import android.hardware.display.AmbientDisplayConfiguration
+import android.os.PowerManager
import android.provider.Settings.Secure.DOZE_DOUBLE_TAP_GESTURE
import android.provider.Settings.Secure.DOZE_TAP_SCREEN_GESTURE
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
-import android.os.PowerManager
import android.view.MotionEvent
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -38,15 +38,14 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidTestingRunner::class)
@RunWithLooper(setAsMainLooper = true)
@@ -112,7 +111,7 @@
// THEN wake up device if dozing
verify(centralSurfaces).wakeUpIfDozing(
- anyLong(), any(), anyString(), eq(PowerManager.WAKE_REASON_TAP))
+ anyLong(), anyString(), eq(PowerManager.WAKE_REASON_TAP))
}
@Test
@@ -132,7 +131,7 @@
// THEN wake up device if dozing
verify(centralSurfaces).wakeUpIfDozing(
- anyLong(), any(), anyString(), eq(PowerManager.WAKE_REASON_TAP))
+ anyLong(), anyString(), eq(PowerManager.WAKE_REASON_TAP))
}
@Test
@@ -164,7 +163,7 @@
// THEN the device doesn't wake up
verify(centralSurfaces, never()).wakeUpIfDozing(
- anyLong(), any(), anyString(), anyInt())
+ anyLong(), anyString(), anyInt())
}
@Test
@@ -212,7 +211,7 @@
// THEN the device doesn't wake up
verify(centralSurfaces, never()).wakeUpIfDozing(
- anyLong(), any(), anyString(), anyInt())
+ anyLong(), anyString(), anyInt())
}
@Test
@@ -232,7 +231,7 @@
// THEN the device doesn't wake up
verify(centralSurfaces, never()).wakeUpIfDozing(
- anyLong(), any(), anyString(), anyInt())
+ anyLong(), anyString(), anyInt())
}
@Test
@@ -252,7 +251,7 @@
// THEN the device doesn't wake up
verify(centralSurfaces, never()).wakeUpIfDozing(
- anyLong(), any(), anyString(), anyInt())
+ anyLong(), anyString(), anyInt())
}
fun updateSettings() {
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/shared/condition/ConditionExtensionsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
new file mode 100644
index 0000000..2b4a7fb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
@@ -0,0 +1,135 @@
+package com.android.systemui.shared.condition
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class ConditionExtensionsTest : SysuiTestCase() {
+ private lateinit var testScope: TestScope
+
+ @Before
+ fun setUp() {
+ testScope = TestScope(StandardTestDispatcher())
+ }
+
+ @Test
+ fun flowInitiallyTrue() =
+ testScope.runTest {
+ val flow = flowOf(true)
+ val condition = flow.toCondition(this)
+
+ runCurrent()
+ assertThat(condition.isConditionSet).isFalse()
+
+ condition.start()
+ runCurrent()
+ assertThat(condition.isConditionSet).isTrue()
+ assertThat(condition.isConditionMet).isTrue()
+ }
+
+ @Test
+ fun flowInitiallyFalse() =
+ testScope.runTest {
+ val flow = flowOf(false)
+ val condition = flow.toCondition(this)
+
+ runCurrent()
+ assertThat(condition.isConditionSet).isFalse()
+
+ condition.start()
+ runCurrent()
+ assertThat(condition.isConditionSet).isTrue()
+ assertThat(condition.isConditionMet).isFalse()
+ }
+
+ @Test
+ fun emptyFlowWithNoInitialValue() =
+ testScope.runTest {
+ val flow = emptyFlow<Boolean>()
+ val condition = flow.toCondition(this)
+ condition.start()
+
+ runCurrent()
+ assertThat(condition.isConditionSet).isFalse()
+ assertThat(condition.isConditionMet).isFalse()
+ }
+
+ @Test
+ fun emptyFlowWithInitialValueOfTrue() =
+ testScope.runTest {
+ val flow = emptyFlow<Boolean>()
+ val condition = flow.toCondition(scope = this, initialValue = true)
+ condition.start()
+
+ runCurrent()
+ assertThat(condition.isConditionSet).isTrue()
+ assertThat(condition.isConditionMet).isTrue()
+ }
+
+ @Test
+ fun emptyFlowWithInitialValueOfFalse() =
+ testScope.runTest {
+ val flow = emptyFlow<Boolean>()
+ val condition = flow.toCondition(scope = this, initialValue = false)
+ condition.start()
+
+ runCurrent()
+ assertThat(condition.isConditionSet).isTrue()
+ assertThat(condition.isConditionMet).isFalse()
+ }
+
+ @Test
+ fun conditionUpdatesWhenFlowEmitsNewValue() =
+ testScope.runTest {
+ val flow = MutableStateFlow(false)
+ val condition = flow.toCondition(this)
+ condition.start()
+
+ runCurrent()
+ assertThat(condition.isConditionSet).isTrue()
+ assertThat(condition.isConditionMet).isFalse()
+
+ flow.value = true
+ runCurrent()
+ assertThat(condition.isConditionMet).isTrue()
+
+ flow.value = false
+ runCurrent()
+ assertThat(condition.isConditionMet).isFalse()
+
+ condition.stop()
+ }
+
+ @Test
+ fun stoppingConditionUnsubscribesFromFlow() =
+ testScope.runTest {
+ val flow = MutableSharedFlow<Boolean>()
+ val condition = flow.toCondition(this)
+ runCurrent()
+ assertThat(flow.subscriptionCount.value).isEqualTo(0)
+
+ condition.start()
+ runCurrent()
+ assertThat(flow.subscriptionCount.value).isEqualTo(1)
+
+ condition.stop()
+ runCurrent()
+ assertThat(flow.subscriptionCount.value).isEqualTo(0)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 932a1f9..d017ffd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -13,7 +13,7 @@
import com.android.systemui.media.controls.ui.MediaHierarchyManager
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.qs.QS
-import com.android.systemui.shade.NotificationPanelViewController
+import com.android.systemui.shade.ShadeViewController
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.NotificationTestHelper
import com.android.systemui.statusbar.notification.stack.AmbientState
@@ -44,8 +44,8 @@
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
private fun <T> anyObject(): T {
return Mockito.anyObject<T>()
@@ -69,7 +69,7 @@
@Mock lateinit var mediaHierarchyManager: MediaHierarchyManager
@Mock lateinit var scrimController: ScrimController
@Mock lateinit var falsingManager: FalsingManager
- @Mock lateinit var notificationPanelController: NotificationPanelViewController
+ @Mock lateinit var shadeViewController: ShadeViewController
@Mock lateinit var nsslController: NotificationStackScrollLayoutController
@Mock lateinit var depthController: NotificationShadeDepthController
@Mock lateinit var stackscroller: NotificationStackScrollLayout
@@ -128,7 +128,7 @@
transitionController.addCallback(transitionControllerCallback)
whenever(nsslController.view).thenReturn(stackscroller)
whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback)
- transitionController.notificationPanelController = notificationPanelController
+ transitionController.shadeViewController = shadeViewController
transitionController.centralSurfaces = mCentralSurfaces
transitionController.qS = qS
transitionController.setStackScroller(nsslController)
@@ -223,7 +223,7 @@
fun testGoToLockedShadeCreatesQSAnimation() {
transitionController.goToLockedShade(null)
verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED)
- verify(notificationPanelController).transitionToExpandedShade(anyLong())
+ verify(shadeViewController).transitionToExpandedShade(anyLong())
assertNotNull(transitionController.dragDownAnimator)
}
@@ -231,7 +231,7 @@
fun testGoToLockedShadeDoesntCreateQSAnimation() {
transitionController.goToLockedShade(null, needsQSAnimation = false)
verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED)
- verify(notificationPanelController).transitionToExpandedShade(anyLong())
+ verify(shadeViewController).transitionToExpandedShade(anyLong())
assertNull(transitionController.dragDownAnimator)
}
@@ -239,7 +239,7 @@
fun testGoToLockedShadeAlwaysCreatesQSAnimationInSplitShade() {
enableSplitShade()
transitionController.goToLockedShade(null, needsQSAnimation = true)
- verify(notificationPanelController).transitionToExpandedShade(anyLong())
+ verify(shadeViewController).transitionToExpandedShade(anyLong())
assertNotNull(transitionController.dragDownAnimator)
}
@@ -293,7 +293,7 @@
fun setDragAmount_setsKeyguardTransitionProgress() {
transitionController.dragDownAmount = 10f
- verify(notificationPanelController).setKeyguardTransitionProgress(anyFloat(), anyInt())
+ verify(shadeViewController).setKeyguardTransitionProgress(anyFloat(), anyInt())
}
@Test
@@ -303,7 +303,7 @@
transitionController.dragDownAmount = 10f
val expectedAlpha = 1 - 10f / alphaDistance
- verify(notificationPanelController)
+ verify(shadeViewController)
.setKeyguardTransitionProgress(eq(expectedAlpha), anyInt())
}
@@ -317,7 +317,7 @@
transitionController.dragDownAmount = 10f
- verify(notificationPanelController).setKeyguardTransitionProgress(anyFloat(), eq(0))
+ verify(shadeViewController).setKeyguardTransitionProgress(anyFloat(), eq(0))
}
@Test
@@ -330,7 +330,7 @@
transitionController.dragDownAmount = 10f
- verify(notificationPanelController)
+ verify(shadeViewController)
.setKeyguardTransitionProgress(anyFloat(), eq(mediaTranslationY))
}
@@ -349,7 +349,7 @@
context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_keyguard_transition_vertical_offset)
val expectedTranslation = 10f / distance * offset
- verify(notificationPanelController)
+ verify(shadeViewController)
.setKeyguardTransitionProgress(anyFloat(), eq(expectedTranslation.toInt()))
}
@@ -468,7 +468,7 @@
transitionController.dragDownAmount = dragDownAmount
val expectedAlpha = 1 - dragDownAmount / alphaDistance
- verify(notificationPanelController).setKeyguardStatusBarAlpha(expectedAlpha)
+ verify(shadeViewController).setKeyguardStatusBarAlpha(expectedAlpha)
}
@Test
@@ -477,7 +477,7 @@
transitionController.dragDownAmount = 10f
- verify(notificationPanelController).setKeyguardStatusBarAlpha(-1f)
+ verify(shadeViewController).setKeyguardStatusBarAlpha(-1f)
}
private fun enableSplitShade() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
new file mode 100644
index 0000000..b997f64
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
@@ -0,0 +1,175 @@
+/*
+ * 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.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 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
+import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.doCallRealMethod
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+@RunWithLooper
+class NotificationMediaManagerTest : SysuiTestCase() {
+
+ @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(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,
+ )
+ }
+
+ /**
+ * 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() {
+ mockManager.mIsLockscreenLiveWallpaperEnabled = true
+ for (metaDataChanged in listOf(true, false)) {
+ for (allowEnterAnimation in listOf(true, false)) {
+ 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/notification/NotificationWakeUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
index aff705f..da3a9f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
@@ -23,7 +23,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.shade.NotificationPanelViewController.WAKEUP_ANIMATION_DELAY_MS
+import com.android.systemui.shade.ShadeViewController.Companion.WAKEUP_ANIMATION_DELAY_MS
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_WAKEUP
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index ba91d87..67128ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -22,7 +22,6 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.logcatLogBuffer
-import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.NotificationRemoteInputManager
import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
@@ -171,9 +170,6 @@
// Set the default FSI decision
setShouldFullScreen(any(), FullScreenIntentDecision.NO_FULL_SCREEN_INTENT)
-
- // Run tests with default feature flag state
- whenever(flags.fsiOnDNDUpdate()).thenReturn(Flags.FSI_ON_DND_UPDATE.default)
}
@Test
@@ -258,7 +254,7 @@
@Test
fun testOnEntryAdded_shouldFullScreen() {
- setShouldFullScreen(entry, FullScreenIntentDecision.FSI_EXPECTED_NOT_TO_HUN)
+ setShouldFullScreen(entry, FullScreenIntentDecision.FSI_KEYGUARD_SHOWING)
collectionListener.onEntryAdded(entry)
verify(launchFullScreenIntentProvider).launchFullScreenIntent(entry)
}
@@ -854,38 +850,7 @@
}
@Test
- fun testOnRankingApplied_noFSIOnUpdateWhenFlagOff() {
- // Ensure the feature flag is off
- whenever(flags.fsiOnDNDUpdate()).thenReturn(false)
-
- // GIVEN that mEntry was previously suppressed from full-screen only by DND
- setShouldFullScreen(entry, FullScreenIntentDecision.NO_FSI_SUPPRESSED_ONLY_BY_DND)
- collectionListener.onEntryAdded(entry)
-
- // Verify that this causes a log
- verifyLoggedFullScreenIntentDecision(
- entry,
- FullScreenIntentDecision.NO_FSI_SUPPRESSED_ONLY_BY_DND
- )
- clearInterruptionProviderInvocations()
-
- // and it is then updated to allow full screen
- setShouldFullScreen(entry, FullScreenIntentDecision.FSI_DEVICE_NOT_INTERACTIVE)
- whenever(notifPipeline.allNotifs).thenReturn(listOf(entry))
- collectionListener.onRankingApplied()
-
- // THEN it should not full screen because the feature is off
- verify(launchFullScreenIntentProvider, never()).launchFullScreenIntent(any())
-
- // VERIFY that no additional logging happens either
- verifyNoFullScreenIntentDecisionLogged()
- }
-
- @Test
fun testOnRankingApplied_updateToFullScreen() {
- // Turn on the feature
- whenever(flags.fsiOnDNDUpdate()).thenReturn(true)
-
// GIVEN that mEntry was previously suppressed from full-screen only by DND
setShouldFullScreen(entry, FullScreenIntentDecision.NO_FSI_SUPPRESSED_ONLY_BY_DND)
collectionListener.onEntryAdded(entry)
@@ -929,9 +894,6 @@
@Test
fun testOnRankingApplied_withOnlyDndSuppressionAllowsFsiLater() {
- // Turn on the feature
- whenever(flags.fsiOnDNDUpdate()).thenReturn(true)
-
// GIVEN that mEntry was previously suppressed from full-screen only by DND
setShouldFullScreen(entry, FullScreenIntentDecision.NO_FSI_SUPPRESSED_ONLY_BY_DND)
collectionListener.onEntryAdded(entry)
@@ -980,9 +942,6 @@
@Test
fun testOnRankingApplied_newNonFullScreenAnswerInvalidatesCandidate() {
- // Turn on the feature
- whenever(flags.fsiOnDNDUpdate()).thenReturn(true)
-
// GIVEN that mEntry was previously suppressed from full-screen only by DND
whenever(notifPipeline.allNotifs).thenReturn(listOf(entry))
setShouldFullScreen(entry, FullScreenIntentDecision.NO_FSI_SUPPRESSED_ONLY_BY_DND)
@@ -1018,9 +977,6 @@
@Test
fun testOnRankingApplied_noFSIWhenAlsoSuppressedForOtherReasons() {
- // Feature on
- whenever(flags.fsiOnDNDUpdate()).thenReturn(true)
-
// GIVEN that mEntry is suppressed by DND (functionally), but not *only* DND
setShouldFullScreen(entry, FullScreenIntentDecision.NO_FSI_SUPPRESSED_BY_DND)
collectionListener.onEntryAdded(entry)
@@ -1035,9 +991,6 @@
@Test
fun testOnRankingApplied_noFSIWhenTooOld() {
- // Feature on
- whenever(flags.fsiOnDNDUpdate()).thenReturn(true)
-
// GIVEN that mEntry is suppressed only by DND
setShouldFullScreen(entry, FullScreenIntentDecision.NO_FSI_SUPPRESSED_ONLY_BY_DND)
collectionListener.onEntryAdded(entry)
@@ -1046,7 +999,7 @@
coordinator.addForFSIReconsideration(entry, systemClock.currentTimeMillis() - 10000)
// and it is updated to full screen later
- setShouldFullScreen(entry, FullScreenIntentDecision.FSI_EXPECTED_NOT_TO_HUN)
+ setShouldFullScreen(entry, FullScreenIntentDecision.FSI_KEYGUARD_SHOWING)
collectionListener.onRankingApplied()
// THEN it should still not full screen because it's too old
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index c2a2a40..8f07f8d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -97,8 +97,6 @@
@Test
fun unseenFilterSuppressesSeenNotifWhileKeyguardShowing() {
- whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
-
// GIVEN: Keyguard is not showing, shade is expanded, and a notification is present
keyguardRepository.setKeyguardShowing(false)
whenever(statusBarStateController.isExpanded).thenReturn(true)
@@ -124,8 +122,6 @@
@Test
fun unseenFilterStopsMarkingSeenNotifWhenTransitionToAod() {
- whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
-
// GIVEN: Keyguard is not showing, shade is not expanded, and a notification is present
keyguardRepository.setKeyguardShowing(false)
whenever(statusBarStateController.isExpanded).thenReturn(false)
@@ -151,8 +147,6 @@
@Test
fun unseenFilter_headsUpMarkedAsSeen() {
- whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
-
// GIVEN: Keyguard is not showing, shade is not expanded
keyguardRepository.setKeyguardShowing(false)
whenever(statusBarStateController.isExpanded).thenReturn(false)
@@ -183,14 +177,12 @@
@Test
fun unseenFilterDoesNotSuppressSeenOngoingNotifWhileKeyguardShowing() {
- whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
-
// GIVEN: Keyguard is not showing, shade is expanded, and an ongoing notification is present
keyguardRepository.setKeyguardShowing(false)
whenever(statusBarStateController.isExpanded).thenReturn(true)
runKeyguardCoordinatorTest {
val fakeEntry = NotificationEntryBuilder()
- .setNotification(Notification.Builder(mContext).setOngoing(true).build())
+ .setNotification(Notification.Builder(mContext, "id").setOngoing(true).build())
.build()
collectionListener.onEntryAdded(fakeEntry)
@@ -205,8 +197,6 @@
@Test
fun unseenFilterDoesNotSuppressSeenMediaNotifWhileKeyguardShowing() {
- whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
-
// GIVEN: Keyguard is not showing, shade is expanded, and a media notification is present
keyguardRepository.setKeyguardShowing(false)
whenever(statusBarStateController.isExpanded).thenReturn(true)
@@ -229,8 +219,6 @@
@Test
fun unseenFilterUpdatesSeenProviderWhenSuppressing() {
- whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
-
// GIVEN: Keyguard is not showing, shade is expanded, and a notification is present
keyguardRepository.setKeyguardShowing(false)
whenever(statusBarStateController.isExpanded).thenReturn(true)
@@ -255,8 +243,6 @@
@Test
fun unseenFilterInvalidatesWhenSettingChanges() {
- whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
-
// GIVEN: Keyguard is not showing, and shade is expanded
keyguardRepository.setKeyguardShowing(false)
whenever(statusBarStateController.isExpanded).thenReturn(true)
@@ -292,8 +278,6 @@
@Test
fun unseenFilterAllowsNewNotif() {
- whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
-
// GIVEN: Keyguard is showing, no notifications present
keyguardRepository.setKeyguardShowing(true)
runKeyguardCoordinatorTest {
@@ -308,8 +292,6 @@
@Test
fun unseenFilterSeenGroupSummaryWithUnseenChild() {
- whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
-
// GIVEN: Keyguard is not showing, shade is expanded, and a notification is present
keyguardRepository.setKeyguardShowing(false)
whenever(statusBarStateController.isExpanded).thenReturn(true)
@@ -342,8 +324,6 @@
@Test
fun unseenNotificationIsMarkedAsSeenWhenKeyguardGoesAway() {
- whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
-
// GIVEN: Keyguard is showing, not dozing, unseen notification is present
keyguardRepository.setKeyguardShowing(true)
keyguardRepository.setDozing(false)
@@ -370,8 +350,6 @@
@Test
fun unseenNotificationIsNotMarkedAsSeenIfShadeNotExpanded() {
- whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
-
// GIVEN: Keyguard is showing, unseen notification is present
keyguardRepository.setKeyguardShowing(true)
runKeyguardCoordinatorTest {
@@ -441,20 +419,15 @@
val unseenFilter: NotifFilter
get() = keyguardCoordinator.unseenNotifFilter
- // TODO(254647461): Remove lazy from these properties once
- // Flags.FILTER_UNSEEN_NOTIFS_ON_KEYGUARD is enabled and removed
-
- val collectionListener: NotifCollectionListener by lazy {
- withArgCaptor { verify(notifPipeline).addCollectionListener(capture()) }
+ val collectionListener: NotifCollectionListener = withArgCaptor {
+ verify(notifPipeline).addCollectionListener(capture())
}
- val onHeadsUpChangedListener: OnHeadsUpChangedListener by lazy {
+ val onHeadsUpChangedListener: OnHeadsUpChangedListener get() =
withArgCaptor { verify(headsUpManager).addListener(capture()) }
- }
- val statusBarStateListener: StatusBarStateController.StateListener by lazy {
+ val statusBarStateListener: StatusBarStateController.StateListener get() =
withArgCaptor { verify(statusBarStateController).addCallback(capture()) }
- }
var showOnlyUnseenNotifsOnKeyguardSetting: Boolean
get() =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index ae6ced4..d3e5816 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -123,7 +123,6 @@
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(false);
when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
mUiEventLoggerFake = new UiEventLoggerFake();
@@ -544,12 +543,6 @@
}
@Test
- public void testShouldNotFullScreen_notPendingIntent_withStrictFlag() throws Exception {
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
- testShouldNotFullScreen_notPendingIntent();
- }
-
- @Test
public void testShouldNotFullScreen_notPendingIntent() throws RemoteException {
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
when(mPowerManager.isInteractive()).thenReturn(true);
@@ -604,12 +597,6 @@
}
@Test
- public void testShouldNotFullScreen_notHighImportance_withStrictFlag() throws Exception {
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
- testShouldNotFullScreen_notHighImportance();
- }
-
- @Test
public void testShouldNotFullScreen_notHighImportance() throws RemoteException {
NotificationEntry entry = createFsiNotification(IMPORTANCE_DEFAULT, /* silenced */ false);
when(mPowerManager.isInteractive()).thenReturn(true);
@@ -626,12 +613,6 @@
}
@Test
- public void testShouldNotFullScreen_isGroupAlertSilenced_withStrictFlag() throws Exception {
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
- testShouldNotFullScreen_isGroupAlertSilenced();
- }
-
- @Test
public void testShouldNotFullScreen_isGroupAlertSilenced() throws RemoteException {
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ true);
when(mPowerManager.isInteractive()).thenReturn(false);
@@ -656,12 +637,6 @@
}
@Test
- public void testShouldNotFullScreen_isSuppressedByBubbleMetadata_withStrictFlag() {
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
- testShouldNotFullScreen_isSuppressedByBubbleMetadata();
- }
-
- @Test
public void testShouldNotFullScreen_isSuppressedByBubbleMetadata() {
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
Notification.BubbleMetadata bubbleMetadata = new Notification.BubbleMetadata.Builder("foo")
@@ -689,12 +664,6 @@
}
@Test
- public void testShouldFullScreen_notInteractive_withStrictFlag() throws Exception {
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
- testShouldFullScreen_notInteractive();
- }
-
- @Test
public void testShouldFullScreen_notInteractive() throws RemoteException {
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
Notification.BubbleMetadata bubbleMetadata = new Notification.BubbleMetadata.Builder("foo")
@@ -714,12 +683,6 @@
}
@Test
- public void testShouldFullScreen_isDreaming_withStrictFlag() throws Exception {
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
- testShouldFullScreen_isDreaming();
- }
-
- @Test
public void testShouldFullScreen_isDreaming() throws RemoteException {
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
when(mPowerManager.isInteractive()).thenReturn(true);
@@ -736,12 +699,6 @@
}
@Test
- public void testShouldFullScreen_onKeyguard_withStrictFlag() throws Exception {
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
- testShouldFullScreen_onKeyguard();
- }
-
- @Test
public void testShouldFullScreen_onKeyguard() throws RemoteException {
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
when(mPowerManager.isInteractive()).thenReturn(true);
@@ -758,12 +715,6 @@
}
@Test
- public void testShouldNotFullScreen_willHun_withStrictFlag() throws Exception {
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
- testShouldNotFullScreen_willHun();
- }
-
- @Test
public void testShouldNotFullScreen_willHun() throws RemoteException {
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
when(mPowerManager.isInteractive()).thenReturn(true);
@@ -781,26 +732,7 @@
}
@Test
- public void testShouldFullScreen_packageSnoozed() throws RemoteException {
- NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
- when(mPowerManager.isInteractive()).thenReturn(true);
- when(mPowerManager.isScreenOn()).thenReturn(true);
- when(mStatusBarStateController.isDreaming()).thenReturn(false);
- when(mStatusBarStateController.getState()).thenReturn(SHADE);
- when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
-
- assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
- .isEqualTo(FullScreenIntentDecision.FSI_EXPECTED_NOT_TO_HUN);
- assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
- .isTrue();
- verify(mLogger, never()).logNoFullscreen(any(), any());
- verify(mLogger, never()).logNoFullscreenWarning(any(), any());
- verify(mLogger).logFullscreen(entry, "FSI_EXPECTED_NOT_TO_HUN");
- }
-
- @Test
- public void testShouldNotFullScreen_snoozed_occluding_withStrictRules() throws Exception {
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
+ public void testShouldNotFullScreen_snoozed_occluding() throws Exception {
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
when(mPowerManager.isInteractive()).thenReturn(true);
when(mPowerManager.isScreenOn()).thenReturn(true);
@@ -820,8 +752,7 @@
}
@Test
- public void testShouldHeadsUp_snoozed_occluding_withStrictRules() throws Exception {
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
+ public void testShouldHeadsUp_snoozed_occluding() throws Exception {
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
when(mPowerManager.isInteractive()).thenReturn(true);
when(mPowerManager.isScreenOn()).thenReturn(true);
@@ -845,8 +776,7 @@
}
@Test
- public void testShouldNotFullScreen_snoozed_lockedShade_withStrictRules() throws Exception {
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
+ public void testShouldNotFullScreen_snoozed_lockedShade() throws Exception {
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
when(mPowerManager.isInteractive()).thenReturn(true);
when(mPowerManager.isScreenOn()).thenReturn(true);
@@ -866,8 +796,7 @@
}
@Test
- public void testShouldHeadsUp_snoozed_lockedShade_withStrictRules() throws Exception {
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
+ public void testShouldHeadsUp_snoozed_lockedShade() throws Exception {
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
when(mPowerManager.isInteractive()).thenReturn(true);
when(mPowerManager.isScreenOn()).thenReturn(true);
@@ -891,8 +820,7 @@
}
@Test
- public void testShouldNotFullScreen_snoozed_unlocked_withStrictRules() throws Exception {
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
+ public void testShouldNotFullScreen_snoozed_unlocked() throws Exception {
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
when(mPowerManager.isInteractive()).thenReturn(true);
when(mPowerManager.isScreenOn()).thenReturn(true);
@@ -955,8 +883,7 @@
}
@Test
- public void testShouldHeadsUp_snoozed_unlocked_withStrictRules() throws Exception {
- when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
+ public void testShouldHeadsUp_snoozed_unlocked() throws Exception {
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
when(mPowerManager.isInteractive()).thenReturn(true);
when(mPowerManager.isScreenOn()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index 60bc3a4..c2f1f61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -25,7 +25,6 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.PluginManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -145,8 +144,6 @@
@Test
fun offerKeepInParent_parentDismissed() {
- whenever(featureFlags.isEnabled(Flags.NOTIFICATION_GROUP_DISMISSAL_ANIMATION))
- .thenReturn(true)
whenever(view.isParentDismissed).thenReturn(true)
Assert.assertTrue(controller.offerToKeepInParentForAnimation())
@@ -155,9 +152,6 @@
@Test
fun offerKeepInParent_parentNotDismissed() {
- whenever(featureFlags.isEnabled(Flags.NOTIFICATION_GROUP_DISMISSAL_ANIMATION))
- .thenReturn(true)
-
Assert.assertFalse(controller.offerToKeepInParentForAnimation())
Mockito.verify(view, never()).setKeepInParentForDismissAnimation(anyBoolean())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
new file mode 100644
index 0000000..c960230
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.notification.row.ui.viewmodel
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.FakeAccessibilityRepository
+import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor
+import com.android.systemui.coroutines.collectLastValue
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ActivatableNotificationViewModelTest : SysuiTestCase() {
+
+ // fakes
+ private val a11yRepo = FakeAccessibilityRepository()
+
+ // real impls
+ private val a11yInteractor = AccessibilityInteractor(a11yRepo)
+ private val underTest = ActivatableNotificationViewModel(a11yInteractor)
+
+ @Test
+ fun isTouchable_whenA11yTouchExplorationDisabled() = runTest {
+ a11yRepo.isTouchExplorationEnabled.value = false
+ val isTouchable: Boolean? by collectLastValue(underTest.isTouchable)
+ assertThat(isTouchable).isTrue()
+ }
+
+ @Test
+ fun isNotTouchable_whenA11yTouchExplorationEnabled() = runTest {
+ a11yRepo.isTouchExplorationEnabled.value = true
+ val isTouchable: Boolean? by collectLastValue(underTest.isTouchable)
+ assertThat(isTouchable).isFalse()
+ }
+
+ @Test
+ fun isTouchable_whenA11yTouchExplorationChangesToDisabled() = runTest {
+ a11yRepo.isTouchExplorationEnabled.value = true
+ val isTouchable: Boolean? by collectLastValue(underTest.isTouchable)
+ runCurrent()
+ a11yRepo.isTouchExplorationEnabled.value = false
+ assertThat(isTouchable).isTrue()
+ }
+
+ @Test
+ fun isNotTouchable_whenA11yTouchExplorationChangesToEnabled() = runTest {
+ a11yRepo.isTouchExplorationEnabled.value = false
+ val isTouchable: Boolean? by collectLastValue(underTest.isTouchable)
+ runCurrent()
+ a11yRepo.isTouchExplorationEnabled.value = true
+ assertThat(isTouchable).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
index 2cc375b..944eb2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
@@ -18,17 +18,27 @@
package com.android.systemui.statusbar.notification.shelf.domain.interactor
+import android.os.PowerManager
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.statusbar.LockscreenShadeTransitionController
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.Mockito.isNull
+import org.mockito.Mockito.verify
@RunWith(AndroidTestingRunner::class)
@SmallTest
@@ -36,8 +46,17 @@
private val keyguardRepository = FakeKeyguardRepository()
private val deviceEntryFaceAuthRepository = FakeDeviceEntryFaceAuthRepository()
+ private val centralSurfaces: CentralSurfaces = mock()
+ private val systemClock = FakeSystemClock()
+ private val keyguardTransitionController: LockscreenShadeTransitionController = mock()
private val underTest =
- NotificationShelfInteractor(keyguardRepository, deviceEntryFaceAuthRepository)
+ NotificationShelfInteractor(
+ keyguardRepository,
+ deviceEntryFaceAuthRepository,
+ centralSurfaces,
+ systemClock,
+ keyguardTransitionController,
+ )
@Test
fun shelfIsNotStatic_whenKeyguardNotShowing() = runTest {
@@ -85,4 +104,19 @@
assertThat(onKeyguard).isFalse()
}
+
+ @Test
+ fun goToLockedShadeFromShelf_wakesUpFromDoze() {
+ underTest.goToLockedShadeFromShelf()
+
+ verify(centralSurfaces)
+ .wakeUpIfDozing(anyLong(), any(), eq(PowerManager.WAKE_REASON_GESTURE))
+ }
+
+ @Test
+ fun goToLockedShadeFromShelf_invokesKeyguardTransitionController() {
+ underTest.goToLockedShadeFromShelf()
+
+ verify(keyguardTransitionController).goToLockedShade(isNull(), eq(true))
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
index 439edaf..e9a8f3f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
@@ -18,28 +18,64 @@
package com.android.systemui.statusbar.notification.shelf.ui.viewmodel
+import android.os.PowerManager
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.FakeAccessibilityRepository
+import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.statusbar.LockscreenShadeTransitionController
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModel
import com.android.systemui.statusbar.notification.shelf.domain.interactor.NotificationShelfInteractor
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
@RunWith(AndroidTestingRunner::class)
@SmallTest
class NotificationShelfViewModelTest : SysuiTestCase() {
+ @Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ // mocks
+ @Mock private lateinit var centralSurfaces: CentralSurfaces
+ @Mock private lateinit var keyguardTransitionController: LockscreenShadeTransitionController
+
+ // fakes
private val keyguardRepository = FakeKeyguardRepository()
private val deviceEntryFaceAuthRepository = FakeDeviceEntryFaceAuthRepository()
- private val interactor =
- NotificationShelfInteractor(keyguardRepository, deviceEntryFaceAuthRepository)
- private val underTest = NotificationShelfViewModel(interactor)
+ private val systemClock = FakeSystemClock()
+ private val a11yRepo = FakeAccessibilityRepository()
+
+ // real impls
+ private val a11yInteractor = AccessibilityInteractor(a11yRepo)
+ private val activatableViewModel = ActivatableNotificationViewModel(a11yInteractor)
+ private val interactor by lazy {
+ NotificationShelfInteractor(
+ keyguardRepository,
+ deviceEntryFaceAuthRepository,
+ centralSurfaces,
+ systemClock,
+ keyguardTransitionController,
+ )
+ }
+ private val underTest by lazy { NotificationShelfViewModel(interactor, activatableViewModel) }
@Test
fun canModifyColorOfNotifications_whenKeyguardNotShowing() = runTest {
@@ -87,4 +123,13 @@
assertThat(isClickable).isFalse()
}
+
+ @Test
+ fun onClicked_goesToLockedShade() {
+ underTest.onShelfClicked()
+
+ verify(centralSurfaces)
+ .wakeUpIfDozing(ArgumentMatchers.anyLong(), any(), eq(PowerManager.WAKE_REASON_GESTURE))
+ verify(keyguardTransitionController).goToLockedShade(Mockito.isNull(), eq(true))
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 485f2be..45b1f4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -403,7 +403,6 @@
@Test
public void testSetNotifStats_updatesHasFilteredOutSeenNotifications() {
- when(mNotifPipelineFlags.getShouldFilterUnseenNotifsOnKeyguard()).thenReturn(true);
mSeenNotificationsProvider.setHasFilteredOutSeenNotifications(true);
mController.attach(mNotificationStackScrollLayout);
mController.getNotifStackController().setNotifStats(NotifStats.getEmpty());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index 775d267..872c560 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
@@ -46,9 +46,9 @@
import com.android.systemui.qs.QSHost;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.CameraLauncher;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.QuickSettingsController;
import com.android.systemui.shade.ShadeController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
@@ -76,7 +76,7 @@
@Mock private ShadeController mShadeController;
@Mock private CommandQueue mCommandQueue;
@Mock private QuickSettingsController mQuickSettingsController;
- @Mock private NotificationPanelViewController mNotificationPanelViewController;
+ @Mock private ShadeViewController mShadeViewController;
@Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private final MetricsLogger mMetricsLogger = new FakeMetricsLogger();
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -110,7 +110,7 @@
mContext.getResources(),
mShadeController,
mCommandQueue,
- mNotificationPanelViewController,
+ mShadeViewController,
mRemoteInputQuickSettingsDisabler,
mMetricsLogger,
mKeyguardUpdateMonitor,
@@ -153,9 +153,9 @@
// Trying to open it does nothing.
mSbcqCallbacks.animateExpandNotificationsPanel();
- verify(mNotificationPanelViewController, never()).expandToNotifications();
+ verify(mShadeViewController, never()).expandToNotifications();
mSbcqCallbacks.animateExpandSettingsPanel(null);
- verify(mNotificationPanelViewController, never()).expand(anyBoolean());
+ verify(mShadeViewController, never()).expand(anyBoolean());
}
@Test
@@ -171,9 +171,9 @@
// Can now be opened.
mSbcqCallbacks.animateExpandNotificationsPanel();
- verify(mNotificationPanelViewController).expandToNotifications();
+ verify(mShadeViewController).expandToNotifications();
mSbcqCallbacks.animateExpandSettingsPanel(null);
- verify(mNotificationPanelViewController).expandToQs();
+ verify(mShadeViewController).expandToQs();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 6332069..ff3cea5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -387,7 +387,6 @@
when(mStackScroller.generateLayoutParams(any())).thenReturn(new LayoutParams(0, 0));
when(mNotificationPanelView.getLayoutParams()).thenReturn(new LayoutParams(0, 0));
when(mPowerManagerService.isInteractive()).thenReturn(true);
- when(mStackScroller.getActivatedChild()).thenReturn(null);
doAnswer(invocation -> {
OnDismissAction onDismissAction = (OnDismissAction) invocation.getArguments()[0];
@@ -562,7 +561,7 @@
// TODO: we should be able to call mCentralSurfaces.start() and have all the below values
// initialized automatically and make NPVC private.
mCentralSurfaces.mNotificationShadeWindowView = mNotificationShadeWindowView;
- mCentralSurfaces.mNotificationPanelViewController = mNotificationPanelViewController;
+ mCentralSurfaces.mShadeSurface = mNotificationPanelViewController;
mCentralSurfaces.mQsController = mQuickSettingsController;
mCentralSurfaces.mDozeScrimController = mDozeScrimController;
mCentralSurfaces.mPresenter = mNotificationPresenter;
@@ -1206,34 +1205,6 @@
}
@Test
- public void collapseShadeForBugReport_callsanimateCollapseShade_whenFlagDisabled() {
- // GIVEN the shade is expanded & flag enabled
- mCentralSurfaces.onShadeExpansionFullyChanged(true);
- mCentralSurfaces.setBarStateForTest(SHADE);
- mFeatureFlags.set(Flags.LEAVE_SHADE_OPEN_FOR_BUGREPORT, false);
-
- // WHEN collapseShadeForBugreport is called
- mCentralSurfaces.collapseShadeForBugreport();
-
- // VERIFY that animateCollapseShade is called
- verify(mShadeController).animateCollapseShade();
- }
-
- @Test
- public void collapseShadeForBugReport_doesNotCallanimateCollapseShade_whenFlagEnabled() {
- // GIVEN the shade is expanded & flag enabled
- mCentralSurfaces.onShadeExpansionFullyChanged(true);
- mCentralSurfaces.setBarStateForTest(SHADE);
- mFeatureFlags.set(Flags.LEAVE_SHADE_OPEN_FOR_BUGREPORT, true);
-
- // WHEN collapseShadeForBugreport is called
- mCentralSurfaces.collapseShadeForBugreport();
-
- // VERIFY that animateCollapseShade is called
- verify(mShadeController, never()).animateCollapseShade();
- }
-
- @Test
public void deviceStateChange_unfolded_shadeOpen_setsLeaveOpenOnKeyguardHide() {
setFoldedStates(FOLD_STATE_FOLDED);
setGoToSleepStates(FOLD_STATE_FOLDED);
@@ -1327,7 +1298,7 @@
// WHEN wakeup is requested
final int wakeReason = PowerManager.WAKE_REASON_TAP;
- mCentralSurfaces.wakeUpIfDozing(0, null, "", wakeReason);
+ mCentralSurfaces.wakeUpIfDozing(0, "", wakeReason);
// THEN power manager receives wakeup
verify(mPowerManagerService).wakeUp(eq(0L), eq(wakeReason), anyString(), anyString());
@@ -1341,7 +1312,7 @@
// WHEN wakeup is requested
final int wakeReason = PowerManager.WAKE_REASON_TAP;
- mCentralSurfaces.wakeUpIfDozing(0, null, "", wakeReason);
+ mCentralSurfaces.wakeUpIfDozing(0, "", wakeReason);
// THEN power manager receives wakeup
verify(mPowerManagerService, never()).wakeUp(anyLong(), anyInt(), anyString(), anyString());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 996851e..2831d2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -41,8 +41,8 @@
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowViewController;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarState;
@@ -87,7 +87,7 @@
@Mock private NotificationIconAreaController mNotificationIconAreaController;
@Mock private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- @Mock private NotificationPanelViewController mNotificationPanel;
+ @Mock private ShadeViewController mShadeViewController;
@Mock private View mAmbientIndicationContainer;
@Mock private BiometricUnlockController mBiometricUnlockController;
@Mock private AuthController mAuthController;
@@ -108,7 +108,7 @@
mCentralSurfaces,
mStatusBarKeyguardViewManager,
mNotificationShadeWindowViewController,
- mNotificationPanel,
+ mShadeViewController,
mAmbientIndicationContainer);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 3372dc3..205cebd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -38,8 +38,8 @@
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeHeadsUpTracker;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.HeadsUpStatusBarView;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
@@ -65,8 +65,8 @@
private final NotificationStackScrollLayoutController mStackScrollerController =
mock(NotificationStackScrollLayoutController.class);
- private final NotificationPanelViewController mPanelView =
- mock(NotificationPanelViewController.class);
+ private final ShadeViewController mShadeViewController =
+ mock(ShadeViewController.class);
private final ShadeHeadsUpTracker mShadeHeadsUpTracker = mock(ShadeHeadsUpTracker.class);
private final DarkIconDispatcher mDarkIconDispatcher = mock(DarkIconDispatcher.class);
private HeadsUpAppearanceController mHeadsUpAppearanceController;
@@ -104,7 +104,7 @@
mCommandQueue = mock(CommandQueue.class);
mNotificationRoundnessManager = mock(NotificationRoundnessManager.class);
mFeatureFlag = mock(FeatureFlags.class);
- when(mPanelView.getShadeHeadsUpTracker()).thenReturn(mShadeHeadsUpTracker);
+ when(mShadeViewController.getShadeHeadsUpTracker()).thenReturn(mShadeHeadsUpTracker);
when(mFeatureFlag.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES)).thenReturn(true);
mHeadsUpAppearanceController = new HeadsUpAppearanceController(
mock(NotificationIconAreaController.class),
@@ -116,7 +116,7 @@
mKeyguardStateController,
mCommandQueue,
mStackScrollerController,
- mPanelView,
+ mShadeViewController,
mNotificationRoundnessManager,
mFeatureFlag,
mHeadsUpStatusBarView,
@@ -200,7 +200,7 @@
mKeyguardStateController,
mCommandQueue,
mStackScrollerController,
- mPanelView,
+ mShadeViewController,
mNotificationRoundnessManager,
mFeatureFlag,
mHeadsUpStatusBarView,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 760a90b..e838a480 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -52,7 +52,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.shade.ShadeViewStateProvider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -123,14 +123,14 @@
@Mock private NotificationMediaManager mNotificationMediaManager;
- private TestNotificationPanelViewStateProvider mNotificationPanelViewStateProvider;
+ private TestShadeViewStateProvider mShadeViewStateProvider;
private KeyguardStatusBarView mKeyguardStatusBarView;
private KeyguardStatusBarViewController mController;
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
@Before
public void setup() throws Exception {
- mNotificationPanelViewStateProvider = new TestNotificationPanelViewStateProvider();
+ mShadeViewStateProvider = new TestShadeViewStateProvider();
MockitoAnnotations.initMocks(this);
@@ -158,7 +158,7 @@
mStatusBarIconController,
mIconManagerFactory,
mBatteryMeterViewController,
- mNotificationPanelViewStateProvider,
+ mShadeViewStateProvider,
mKeyguardStateController,
mKeyguardBypassController,
mKeyguardUpdateMonitor,
@@ -358,7 +358,7 @@
mController.onViewAttached();
updateStateToKeyguard();
- mNotificationPanelViewStateProvider.setPanelViewExpandedHeight(0);
+ mShadeViewStateProvider.setPanelViewExpandedHeight(0);
mController.updateViewState();
@@ -370,7 +370,7 @@
mController.onViewAttached();
updateStateToKeyguard();
- mNotificationPanelViewStateProvider.setLockscreenShadeDragProgress(1f);
+ mShadeViewStateProvider.setLockscreenShadeDragProgress(1f);
mController.updateViewState();
@@ -451,7 +451,7 @@
updateStateToKeyguard();
mKeyguardStatusBarView.setVisibility(View.VISIBLE);
- mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(true);
+ mShadeViewStateProvider.setShouldHeadsUpBeVisible(true);
mController.updateForHeadsUp(/* animate= */ false);
assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
@@ -463,10 +463,10 @@
updateStateToKeyguard();
// Start with the opposite state.
- mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(true);
+ mShadeViewStateProvider.setShouldHeadsUpBeVisible(true);
mController.updateForHeadsUp(/* animate= */ false);
- mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(false);
+ mShadeViewStateProvider.setShouldHeadsUpBeVisible(false);
mController.updateForHeadsUp(/* animate= */ false);
assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
@@ -591,10 +591,10 @@
return captor.getValue();
}
- private static class TestNotificationPanelViewStateProvider
- implements NotificationPanelViewController.NotificationPanelViewStateProvider {
+ private static class TestShadeViewStateProvider
+ implements ShadeViewStateProvider {
- TestNotificationPanelViewStateProvider() {}
+ TestShadeViewStateProvider() {}
private float mPanelViewExpandedHeight = 100f;
private boolean mShouldHeadsUpBeVisible = false;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
index 7d9c091..8e1dcf0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -27,6 +27,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationListener;
@@ -75,6 +76,8 @@
@Mock private DemoModeController mDemoModeController;
@Mock
private NotificationIconContainer mAodIcons;
+ @Mock
+ private FeatureFlags mFeatureFlags;
@Before
public void setup() {
@@ -91,6 +94,7 @@
Optional.of(mBubbles),
mDemoModeController,
mDarkIconDispatcher,
+ mFeatureFlags,
mStatusBarWindowController,
mScreenOffAnimationController);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 3edf33b..2d96e59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -27,9 +27,9 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.shade.NotificationPanelViewController
import com.android.systemui.shade.ShadeControllerImpl
import com.android.systemui.shade.ShadeLogger
+import com.android.systemui.shade.ShadeViewController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.unfold.SysUIUnfoldComponent
import com.android.systemui.unfold.config.UnfoldTransitionConfig
@@ -43,11 +43,11 @@
import org.junit.Test
import org.mockito.ArgumentCaptor
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import java.util.Optional
@@ -55,7 +55,7 @@
class PhoneStatusBarViewControllerTest : SysuiTestCase() {
@Mock
- private lateinit var notificationPanelViewController: NotificationPanelViewController
+ private lateinit var shadeViewController: ShadeViewController
@Mock
private lateinit var featureFlags: FeatureFlags
@Mock
@@ -134,58 +134,58 @@
val returnVal = view.onTouchEvent(
MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
assertThat(returnVal).isFalse()
- verify(notificationPanelViewController, never()).handleExternalTouch(any())
+ verify(shadeViewController, never()).handleExternalTouch(any())
}
@Test
fun handleTouchEventFromStatusBar_viewNotEnabled_returnsTrueAndNoViewEvent() {
`when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
- `when`(centralSurfacesImpl.notificationPanelViewController)
- .thenReturn(notificationPanelViewController)
- `when`(notificationPanelViewController.isViewEnabled).thenReturn(false)
+ `when`(centralSurfacesImpl.shadeViewController)
+ .thenReturn(shadeViewController)
+ `when`(shadeViewController.isViewEnabled).thenReturn(false)
val returnVal = view.onTouchEvent(
MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
assertThat(returnVal).isTrue()
- verify(notificationPanelViewController, never()).handleExternalTouch(any())
+ verify(shadeViewController, never()).handleExternalTouch(any())
}
@Test
fun handleTouchEventFromStatusBar_viewNotEnabledButIsMoveEvent_viewReceivesEvent() {
`when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
- `when`(centralSurfacesImpl.notificationPanelViewController)
- .thenReturn(notificationPanelViewController)
- `when`(notificationPanelViewController.isViewEnabled).thenReturn(false)
+ `when`(centralSurfacesImpl.shadeViewController)
+ .thenReturn(shadeViewController)
+ `when`(shadeViewController.isViewEnabled).thenReturn(false)
val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
view.onTouchEvent(event)
- verify(notificationPanelViewController).handleExternalTouch(event)
+ verify(shadeViewController).handleExternalTouch(event)
}
@Test
fun handleTouchEventFromStatusBar_panelAndViewEnabled_viewReceivesEvent() {
`when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
- `when`(centralSurfacesImpl.notificationPanelViewController)
- .thenReturn(notificationPanelViewController)
- `when`(notificationPanelViewController.isViewEnabled).thenReturn(true)
+ `when`(centralSurfacesImpl.shadeViewController)
+ .thenReturn(shadeViewController)
+ `when`(shadeViewController.isViewEnabled).thenReturn(true)
val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 2f, 0)
view.onTouchEvent(event)
- verify(notificationPanelViewController).handleExternalTouch(event)
+ verify(shadeViewController).handleExternalTouch(event)
}
@Test
fun handleTouchEventFromStatusBar_topEdgeTouch_viewNeverReceivesEvent() {
`when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
- `when`(centralSurfacesImpl.notificationPanelViewController)
- .thenReturn(notificationPanelViewController)
- `when`(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+ `when`(centralSurfacesImpl.shadeViewController)
+ .thenReturn(shadeViewController)
+ `when`(shadeViewController.isFullyCollapsed).thenReturn(true)
val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
view.onTouchEvent(event)
- verify(notificationPanelViewController, never()).handleExternalTouch(any())
+ verify(shadeViewController, never()).handleExternalTouch(any())
}
private fun createViewMock(): PhoneStatusBarView {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
index 3ed454f..9c10131 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
@@ -21,7 +21,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.Gefingerpoken
import com.android.systemui.SysuiTestCase
-import com.android.systemui.shade.NotificationPanelViewController
+import com.android.systemui.shade.ShadeViewController
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -32,7 +32,7 @@
class PhoneStatusBarViewTest : SysuiTestCase() {
@Mock
- private lateinit var notificationPanelViewController: NotificationPanelViewController
+ private lateinit var shadeViewController: ShadeViewController
@Mock
private lateinit var panelView: ViewGroup
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 14aee4e..4ff225c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -73,11 +73,11 @@
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.navigationbar.TaskbarDelegate;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shade.ShadeExpansionStateManager;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
@@ -110,7 +110,7 @@
@Mock private LockPatternUtils mLockPatternUtils;
@Mock private CentralSurfaces mCentralSurfaces;
@Mock private ViewGroup mContainer;
- @Mock private NotificationPanelViewController mNotificationPanelView;
+ @Mock private ShadeViewController mShadeViewController;
@Mock private BiometricUnlockController mBiometricUnlockController;
@Mock private SysuiStatusBarStateController mStatusBarStateController;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -202,7 +202,7 @@
.thenReturn(mOnBackInvokedDispatcher);
mStatusBarKeyguardViewManager.registerCentralSurfaces(
mCentralSurfaces,
- mNotificationPanelView,
+ mShadeViewController,
new ShadeExpansionStateManager(),
mBiometricUnlockController,
mNotificationContainer,
@@ -250,7 +250,7 @@
@Test
public void onPanelExpansionChanged_neverShowsDuringHintAnimation() {
- when(mNotificationPanelView.isUnlockHintRunning()).thenReturn(true);
+ when(mShadeViewController.isUnlockHintRunning()).thenReturn(true);
mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
verify(mPrimaryBouncerInteractor, never()).setPanelExpansion(anyFloat());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index ee7e082..d6ae2b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -66,9 +66,9 @@
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowViewController;
import com.android.systemui.shade.ShadeControllerImpl;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.NotificationClickNotifier;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -232,7 +232,7 @@
mOnUserInteractionCallback,
mCentralSurfaces,
mock(NotificationPresenter.class),
- mock(NotificationPanelViewController.class),
+ mock(ShadeViewController.class),
mActivityLaunchAnimator,
notificationAnimationProvider,
mock(LaunchFullScreenIntentProvider.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index e83e50d..fdfe028 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -25,15 +25,12 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.app.StatusBarManager;
-import android.metrics.LogMaker;
-import android.support.test.metricshelper.MetricsAsserts;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.testing.FakeMetricsLogger;
import com.android.systemui.ForegroundServiceNotificationListener;
import com.android.systemui.InitController;
@@ -41,11 +38,11 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.FakeDisplayTracker;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.QuickSettingsController;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeNotificationPresenter;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -61,7 +58,6 @@
import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
@@ -111,12 +107,12 @@
mock(NotificationStackScrollLayout.class));
when(notificationShadeWindowView.getResources()).thenReturn(mContext.getResources());
- NotificationPanelViewController npvc = mock(NotificationPanelViewController.class);
- when(npvc.getShadeNotificationPresenter())
+ ShadeViewController shadeViewController = mock(ShadeViewController.class);
+ when(shadeViewController.getShadeNotificationPresenter())
.thenReturn(mock(ShadeNotificationPresenter.class));
mStatusBarNotificationPresenter = new StatusBarNotificationPresenter(
mContext,
- npvc,
+ shadeViewController,
mock(QuickSettingsController.class),
mock(HeadsUpManagerPhone.class),
notificationShadeWindowView,
@@ -198,46 +194,7 @@
}
@Test
- public void testNoSuppressHeadsUp_FSI_occludedKeygaurd() {
- when(mNotifPipelineFlags.fullScreenIntentRequiresKeyguard()).thenReturn(false);
- Notification n = new Notification.Builder(getContext(), "a")
- .setFullScreenIntent(mock(PendingIntent.class), true)
- .build();
- NotificationEntry entry = new NotificationEntryBuilder()
- .setPkg("a")
- .setOpPkg("a")
- .setTag("a")
- .setNotification(n)
- .build();
-
- when(mKeyguardStateController.isShowing()).thenReturn(true);
- when(mKeyguardStateController.isOccluded()).thenReturn(true);
- when(mCentralSurfaces.isOccluded()).thenReturn(true);
- assertFalse(mInterruptSuppressor.suppressAwakeHeadsUp(entry));
- }
-
- @Test
- public void testSuppressHeadsUp_FSI_nonOccludedKeygaurd() {
- when(mNotifPipelineFlags.fullScreenIntentRequiresKeyguard()).thenReturn(false);
- Notification n = new Notification.Builder(getContext(), "a")
- .setFullScreenIntent(mock(PendingIntent.class), true)
- .build();
- NotificationEntry entry = new NotificationEntryBuilder()
- .setPkg("a")
- .setOpPkg("a")
- .setTag("a")
- .setNotification(n)
- .build();
-
- when(mKeyguardStateController.isShowing()).thenReturn(true);
- when(mKeyguardStateController.isOccluded()).thenReturn(false);
- when(mCentralSurfaces.isOccluded()).thenReturn(false);
- assertTrue(mInterruptSuppressor.suppressAwakeHeadsUp(entry));
- }
-
- @Test
- public void testNoSuppressHeadsUp_FSI_nonOccludedKeygaurd_withNewFlag() {
- when(mNotifPipelineFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
+ public void testNoSuppressHeadsUp_FSI_nonOccludedKeyguard() {
Notification n = new Notification.Builder(getContext(), "a")
.setFullScreenIntent(mock(PendingIntent.class), true)
.build();
@@ -283,15 +240,4 @@
assertTrue("CentralSurfaces alerts disabled shouldn't allow interruptions",
mInterruptSuppressor.suppressInterruptions(entry));
}
-
- @Test
- public void onActivatedMetrics() {
- ActivatableNotificationView view = mock(ActivatableNotificationView.class);
- mStatusBarNotificationPresenter.onActivated(view);
-
- MetricsAsserts.assertHasLog("missing lockscreen note tap log",
- mMetricsLogger.getLogs(),
- new LogMaker(MetricsEvent.ACTION_LS_NOTE)
- .setType(MetricsEvent.TYPE_ACTION));
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
index 02c459b..3c644a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
@@ -25,7 +25,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.WakefulnessLifecycle
-import com.android.systemui.shade.NotificationPanelViewController
+import com.android.systemui.shade.ShadeViewController
import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.StatusBarStateControllerImpl
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -59,9 +59,9 @@
@Mock
private lateinit var globalSettings: GlobalSettings
@Mock
- private lateinit var mCentralSurfaces: CentralSurfaces
+ private lateinit var centralSurfaces: CentralSurfaces
@Mock
- private lateinit var notificationPanelViewController: NotificationPanelViewController
+ private lateinit var shadeViewController: ShadeViewController
@Mock
private lateinit var lightRevealScrim: LightRevealScrim
@Mock
@@ -91,13 +91,13 @@
powerManager,
handler = handler
)
- controller.initialize(mCentralSurfaces, lightRevealScrim)
- `when`(mCentralSurfaces.notificationPanelViewController).thenReturn(
- notificationPanelViewController)
+ controller.initialize(centralSurfaces, lightRevealScrim)
+ `when`(centralSurfaces.shadeViewController).thenReturn(
+ shadeViewController)
// Screen off does not run if the panel is expanded, so we should say it's collapsed to test
// screen off.
- `when`(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+ `when`(shadeViewController.isFullyCollapsed).thenReturn(true)
}
@After
@@ -127,7 +127,7 @@
callbackCaptor.value.run()
- verify(notificationPanelViewController, times(1)).showAodUi()
+ verify(shadeViewController, times(1)).showAodUi()
}
/**
@@ -149,7 +149,7 @@
verify(handler).postDelayed(callbackCaptor.capture(), anyLong())
callbackCaptor.value.run()
- verify(notificationPanelViewController, never()).showAodUi()
+ verify(shadeViewController, never()).showAodUi()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index be0c83f..2a3c775 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -56,8 +56,8 @@
import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.plugins.log.LogcatEchoTracker;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeExpansionStateManager;
+import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
@@ -117,7 +117,7 @@
@Mock
private HeadsUpAppearanceController mHeadsUpAppearanceController;
@Mock
- private NotificationPanelViewController mNotificationPanelViewController;
+ private ShadeViewController mShadeViewController;
@Mock
private StatusBarIconController.DarkIconManager.Factory mIconManagerFactory;
@Mock
@@ -507,7 +507,7 @@
mIconManagerFactory,
mStatusBarHideIconsForBouncerManager,
mKeyguardStateController,
- mNotificationPanelViewController,
+ mShadeViewController,
mStatusBarStateController,
mCommandQueue,
mCarrierConfigTracker,
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/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index 391c8ca..50bb058 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -70,8 +70,6 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -453,17 +451,13 @@
private RemoteInputViewController bindController(
RemoteInputView view,
NotificationEntry entry) {
- FakeFeatureFlags fakeFeatureFlags = new FakeFeatureFlags();
- fakeFeatureFlags.set(Flags.NOTIFICATION_INLINE_REPLY_ANIMATION, true);
RemoteInputViewControllerImpl viewController = new RemoteInputViewControllerImpl(
view,
entry,
mRemoteInputQuickSettingsDisabler,
mController,
mShortcutManager,
- mUiEventLoggerFake,
- fakeFeatureFlags
- );
+ mUiEventLoggerFake);
viewController.bind();
return viewController;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
index 17f8ec2..0b3dd66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusManagerTest.kt
@@ -101,9 +101,12 @@
whenever(stylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true)
whenever(btStylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true)
+ whenever(btStylusDevice.isExternal).thenReturn(true)
+
whenever(stylusDevice.bluetoothAddress).thenReturn(null)
whenever(btStylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS)
+ whenever(btStylusDevice.batteryState).thenReturn(batteryState)
whenever(stylusDevice.batteryState).thenReturn(batteryState)
whenever(batteryState.capacity).thenReturn(0.5f)
@@ -148,6 +151,27 @@
}
@Test
+ fun startListener_hasNotStarted_registersExistingBluetoothDevice() {
+ whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(BT_STYLUS_DEVICE_ID))
+
+ stylusManager =
+ StylusManager(
+ mContext,
+ inputManager,
+ bluetoothAdapter,
+ handler,
+ EXECUTOR,
+ featureFlags,
+ uiEventLogger
+ )
+
+ stylusManager.startListener()
+
+ verify(bluetoothAdapter, times(1))
+ .addOnMetadataChangedListener(bluetoothDevice, EXECUTOR, stylusManager)
+ }
+
+ @Test
fun startListener_hasStarted_doesNothing() {
stylusManager.startListener()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
index dfbd61b..8fc0a1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
@@ -31,8 +31,8 @@
import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.shade.NotificationPanelViewController
import com.android.systemui.shade.ShadeFoldAnimator
+import com.android.systemui.shade.ShadeViewController
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.phone.CentralSurfaces
@@ -74,7 +74,7 @@
@Mock lateinit var lightRevealScrim: LightRevealScrim
- @Mock lateinit var notificationPanelViewController: NotificationPanelViewController
+ @Mock lateinit var shadeViewController: ShadeViewController
@Mock lateinit var viewGroup: ViewGroup
@@ -100,13 +100,12 @@
deviceStates = FoldableTestUtils.findDeviceStates(context)
// TODO(b/254878364): remove this call to NPVC.getView()
- whenever(notificationPanelViewController.shadeFoldAnimator).thenReturn(shadeFoldAnimator)
+ whenever(shadeViewController.shadeFoldAnimator).thenReturn(shadeFoldAnimator)
whenever(shadeFoldAnimator.view).thenReturn(viewGroup)
whenever(viewGroup.viewTreeObserver).thenReturn(viewTreeObserver)
whenever(wakefulnessLifecycle.lastSleepReason)
.thenReturn(PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD)
- whenever(centralSurfaces.notificationPanelViewController)
- .thenReturn(notificationPanelViewController)
+ whenever(centralSurfaces.shadeViewController).thenReturn(shadeViewController)
whenever(shadeFoldAnimator.startFoldToAodAnimation(any(), any(), any())).then {
val onActionStarted = it.arguments[0] as Runnable
onActionStarted.run()
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/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index e33bfd7..e06b43a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -374,7 +374,7 @@
@After
public void teardown() {
if (mDialog != null) {
- mDialog.clearInternalHandleAfterTest();
+ mDialog.clearInternalHandlerAfterTest();
}
}
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 a42acd3..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;
@@ -85,7 +84,6 @@
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.launcher3.icons.BubbleBadgeIconFactory;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -1227,8 +1225,7 @@
mBubbleController,
mBubbleController.getStackView(),
new BubbleIconFactory(mContext,
- mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size)),
- new BubbleBadgeIconFactory(mContext,
+ mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size),
mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
mContext.getResources().getColor(R.color.important_conversation),
mContext.getResources().getDimensionPixelSize(
@@ -1736,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();
}
@@ -1756,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);
}
@@ -1764,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);
@@ -1779,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);
@@ -1788,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);
@@ -1803,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/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeAccessibilityRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeAccessibilityRepository.kt
new file mode 100644
index 0000000..8444c7b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeAccessibilityRepository.kt
@@ -0,0 +1,23 @@
+/*
+ * 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.accessibility.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeAccessibilityRepository(
+ override val isTouchExplorationEnabled: MutableStateFlow<Boolean> = MutableStateFlow(false)
+) : AccessibilityRepository
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/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 46001a7..8c5244e 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -122,8 +122,8 @@
"lastHingeAngle: $lastHingeAngle, " +
"lastHingeAngleBeforeTransition: $lastHingeAngleBeforeTransition"
)
- Trace.setCounter("hinge_angle", angle.toLong())
}
+ Trace.setCounter("DeviceFoldStateProvider#onHingeAngle", angle.toLong())
val currentDirection =
if (angle < lastHingeAngle) FOLD_UPDATE_START_CLOSING else FOLD_UPDATE_START_OPENING
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/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 756dcd2..b68adab 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -361,6 +361,7 @@
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.accessibilityTitle = context.getString(R.string.autofill_save_accessibility_title);
params.windowAnimations = R.style.AutofillSaveAnimation;
+ params.setTrustedOverlay();
show();
}
diff --git a/services/backup/BACKUP_OWNERS b/services/backup/BACKUP_OWNERS
new file mode 100644
index 0000000..f8f4f4f
--- /dev/null
+++ b/services/backup/BACKUP_OWNERS
@@ -0,0 +1,10 @@
+# Bug component: 1193469
+
+jstemmer@google.com
+martinoh@google.com
+millmore@google.com
+niamhfw@google.com
+piee@google.com
+philippov@google.com
+rthakohov@google.com
+sarpm@google.com
\ No newline at end of file
diff --git a/services/backup/OWNERS b/services/backup/OWNERS
index 79709a3..3bd2db1 100644
--- a/services/backup/OWNERS
+++ b/services/backup/OWNERS
@@ -2,12 +2,4 @@
set noparent
-bryanmawhinney@google.com
-jstemmer@google.com
-martinoh@google.com
-millmore@google.com
-niamhfw@google.com
-piee@google.com
-philippov@google.com
-rthakohov@google.com
-sarpm@google.com
+include platform/frameworks/base:/services/backup/BACKUP_OWNERS
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index d2c41a4..efff112 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -900,7 +900,7 @@
String[] args, ShellCallback callback, ResultReceiver resultReceiver)
throws RemoteException {
new CompanionDeviceShellCommand(CompanionDeviceManagerService.this, mAssociationStore,
- mDevicePresenceMonitor, mTransportManager)
+ mDevicePresenceMonitor, mTransportManager, mSystemDataTransferRequestStore)
.exec(this, in, out, err, args, callback, resultReceiver);
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 6de3585..669686ad 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -17,10 +17,12 @@
package com.android.server.companion;
import android.companion.AssociationInfo;
+import android.companion.datatransfer.PermissionSyncRequest;
import android.net.MacAddress;
import android.os.Binder;
import android.os.ShellCommand;
+import com.android.server.companion.datatransfer.SystemDataTransferRequestStore;
import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
import com.android.server.companion.transport.CompanionTransportManager;
@@ -35,14 +37,18 @@
private final CompanionDevicePresenceMonitor mDevicePresenceMonitor;
private final CompanionTransportManager mTransportManager;
+ private final SystemDataTransferRequestStore mSystemDataTransferRequestStore;
+
CompanionDeviceShellCommand(CompanionDeviceManagerService service,
AssociationStore associationStore,
CompanionDevicePresenceMonitor devicePresenceMonitor,
- CompanionTransportManager transportManager) {
+ CompanionTransportManager transportManager,
+ SystemDataTransferRequestStore systemDataTransferRequestStore) {
mService = service;
mAssociationStore = associationStore;
mDevicePresenceMonitor = devicePresenceMonitor;
mTransportManager = transportManager;
+ mSystemDataTransferRequestStore = systemDataTransferRequestStore;
}
@Override
@@ -59,7 +65,7 @@
// TODO(b/212535524): use AssociationInfo.toShortString(), once it's not
// longer referenced in tests.
out.println(association.getPackageName() + " "
- + association.getDeviceMacAddress());
+ + association.getDeviceMacAddress() + " " + association.getId());
}
}
break;
@@ -117,6 +123,17 @@
mTransportManager.createDummyTransport(associationId);
break;
+ case "allow-permission-sync": {
+ int userId = getNextIntArgRequired();
+ associationId = getNextIntArgRequired();
+ boolean enabled = getNextBooleanArgRequired();
+ PermissionSyncRequest request = new PermissionSyncRequest(associationId);
+ request.setUserId(userId);
+ request.setUserConsented(enabled);
+ mSystemDataTransferRequestStore.writeRequest(userId, request);
+ }
+ break;
+
default:
return handleDefaultCommands(cmd);
}
@@ -134,6 +151,15 @@
return Integer.parseInt(getNextArgRequired());
}
+ private boolean getNextBooleanArgRequired() {
+ String arg = getNextArgRequired();
+ if ("true".equalsIgnoreCase(arg) || "false".equalsIgnoreCase(arg)) {
+ return Boolean.parseBoolean(arg);
+ } else {
+ throw new IllegalArgumentException("Expected a boolean argument but was: " + arg);
+ }
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
index 2c5d582..720cefa 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
@@ -120,12 +120,14 @@
return requestsByAssociationId;
}
- void writeRequest(@UserIdInt int userId, SystemDataTransferRequest request) {
+ public void writeRequest(@UserIdInt int userId, SystemDataTransferRequest request) {
Slog.i(LOG_TAG, "Writing request=" + request + " to store.");
ArrayList<SystemDataTransferRequest> cachedRequests;
synchronized (mLock) {
// Write to cache
cachedRequests = readRequestsFromCache(userId);
+ cachedRequests.removeIf(
+ request1 -> request1.getAssociationId() == request.getAssociationId());
cachedRequests.add(request);
mCachedPerUser.set(userId, cachedRequests);
}
diff --git a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
index a8519e3..0457e9a 100644
--- a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
+++ b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
@@ -28,7 +28,6 @@
import com.google.security.cryptauth.lib.securegcm.D2DConnectionContextV1;
import com.google.security.cryptauth.lib.securegcm.D2DHandshakeContext;
import com.google.security.cryptauth.lib.securegcm.D2DHandshakeContext.Role;
-import com.google.security.cryptauth.lib.securegcm.DefaultUkey2Logger;
import com.google.security.cryptauth.lib.securegcm.HandshakeException;
import libcore.io.IoUtils;
@@ -329,7 +328,7 @@
}
mRole = Role.Initiator;
- mHandshakeContext = D2DHandshakeContext.forInitiator(DefaultUkey2Logger.INSTANCE);
+ mHandshakeContext = D2DHandshakeContext.forInitiator();
// Send Client Init
if (DEBUG) {
@@ -350,7 +349,7 @@
if (mHandshakeContext == null) { // Server-side logic
mRole = Role.Responder;
- mHandshakeContext = D2DHandshakeContext.forResponder(DefaultUkey2Logger.INSTANCE);
+ mHandshakeContext = D2DHandshakeContext.forResponder();
// Receive Client Init
if (DEBUG) {
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 4b76127..7fae31c 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -338,6 +338,9 @@
// marked as stopped by the system
@NonNull private final Set<String> mInitialNonStoppedSystemPackages = new ArraySet<>();
+ // A map of preloaded package names and the path to its app metadata file path.
+ private final ArrayMap<String, String> mAppMetadataFilePaths = new ArrayMap<>();
+
/**
* Map of system pre-defined, uniquely named actors; keys are namespace,
* value maps actor name to package name.
@@ -536,6 +539,10 @@
return mInitialNonStoppedSystemPackages;
}
+ public ArrayMap<String, String> getAppMetadataFilePaths() {
+ return mAppMetadataFilePaths;
+ }
+
/**
* Only use for testing. Do NOT use in production code.
* @param readPermissions false to create an empty SystemConfig; true to read the permissions.
@@ -1466,7 +1473,20 @@
} else if (!Boolean.parseBoolean(stopped)) {
mInitialNonStoppedSystemPackages.add(pkgName);
}
- }
+ } break;
+ case "asl-file": {
+ String packageName = parser.getAttributeValue(null, "package");
+ String path = parser.getAttributeValue(null, "path");
+ if (TextUtils.isEmpty(packageName)) {
+ Slog.w(TAG, "<" + name + "> without valid package in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else if (TextUtils.isEmpty(path)) {
+ Slog.w(TAG, "<" + name + "> without valid path in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ mAppMetadataFilePaths.put(packageName, path);
+ }
+ } break;
default: {
Slog.w(TAG, "Tag " + name + " is unknown in "
+ permFile + " at " + parser.getPositionDescription());
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 51d349f..9f9642c 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -5912,22 +5912,24 @@
}
private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
- // the managing app can always modify accounts
- if (isProfileOwner(callingUid)) {
- return true;
- }
- DevicePolicyManager dpm = (DevicePolicyManager) mContext
- .getSystemService(Context.DEVICE_POLICY_SERVICE);
- String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
- if (typesArray == null) {
- return true;
- }
- for (String forbiddenType : typesArray) {
- if (forbiddenType.equals(accountType)) {
- return false;
+ return Binder.withCleanCallingIdentity(() -> {
+ // the managing app can always modify accounts
+ if (isProfileOwner(callingUid)) {
+ return true;
}
- }
- return true;
+ DevicePolicyManager dpm = (DevicePolicyManager) mContext
+ .getSystemService(Context.DEVICE_POLICY_SERVICE);
+ String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
+ if (typesArray == null) {
+ return true;
+ }
+ for (String forbiddenType : typesArray) {
+ if (forbiddenType.equals(accountType)) {
+ return false;
+ }
+ }
+ return true;
+ });
}
private boolean isProfileOwner(int uid) {
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..81dc346 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;
}
}
}
@@ -7311,7 +7316,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);
}
@@ -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/AnrHelper.java b/services/core/java/com/android/server/am/AnrHelper.java
index 16219cd..7d98443 100644
--- a/services/core/java/com/android/server/am/AnrHelper.java
+++ b/services/core/java/com/android/server/am/AnrHelper.java
@@ -22,6 +22,7 @@
import android.content.pm.ApplicationInfo;
import android.os.SystemClock;
import android.os.Trace;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -29,8 +30,12 @@
import com.android.internal.os.TimeoutRecord;
import com.android.server.wm.WindowProcessController;
+import java.io.File;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Set;
import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
@@ -59,13 +64,19 @@
/**
* The keep alive time for the threads in the helper threadpool executor
*/
- private static final int AUX_THREAD_KEEP_ALIVE_SECOND = 10;
+ private static final int DEFAULT_THREAD_KEEP_ALIVE_SECOND = 10;
private static final ThreadFactory sDefaultThreadFactory = r ->
new Thread(r, "AnrAuxiliaryTaskExecutor");
+ private static final ThreadFactory sMainProcessDumpThreadFactory = r ->
+ new Thread(r, "AnrMainProcessDumpThread");
@GuardedBy("mAnrRecords")
private final ArrayList<AnrRecord> mAnrRecords = new ArrayList<>();
+
+ private final Set<Integer> mTempDumpedPids =
+ Collections.synchronizedSet(new ArraySet<Integer>());
+
private final AtomicBoolean mRunning = new AtomicBoolean(false);
private final ActivityManagerService mService;
@@ -80,17 +91,21 @@
private int mProcessingPid = -1;
private final ExecutorService mAuxiliaryTaskExecutor;
+ private final ExecutorService mEarlyDumpExecutor;
AnrHelper(final ActivityManagerService service) {
- this(service, new ThreadPoolExecutor(/* corePoolSize= */ 0, /* maximumPoolSize= */ 1,
- /* keepAliveTime= */ AUX_THREAD_KEEP_ALIVE_SECOND, TimeUnit.SECONDS,
- new LinkedBlockingQueue<>(), sDefaultThreadFactory));
+ // All the ANR threads need to expire after a period of inactivity, given the
+ // ephemeral nature of ANRs and how infrequent they are.
+ this(service, makeExpiringThreadPoolWithSize(1, sDefaultThreadFactory),
+ makeExpiringThreadPoolWithSize(2, sMainProcessDumpThreadFactory));
}
@VisibleForTesting
- AnrHelper(ActivityManagerService service, ExecutorService auxExecutor) {
+ AnrHelper(ActivityManagerService service, ExecutorService auxExecutor,
+ ExecutorService earlyDumpExecutor) {
mService = service;
mAuxiliaryTaskExecutor = auxExecutor;
+ mEarlyDumpExecutor = earlyDumpExecutor;
}
void appNotResponding(ProcessRecord anrProcess, TimeoutRecord timeoutRecord) {
@@ -121,6 +136,12 @@
+ timeoutRecord.mReason);
return;
}
+ if (!mTempDumpedPids.add(incomingPid)) {
+ Slog.i(TAG,
+ "Skip ANR being predumped, pid=" + incomingPid + " "
+ + timeoutRecord.mReason);
+ return;
+ }
for (int i = mAnrRecords.size() - 1; i >= 0; i--) {
if (mAnrRecords.get(i).mPid == incomingPid) {
Slog.i(TAG,
@@ -129,10 +150,24 @@
return;
}
}
+ // We dump the main process as soon as we can on a different thread,
+ // this is done as the main process's dump can go stale in a few hundred
+ // milliseconds and the average full ANR dump takes a few seconds.
+ timeoutRecord.mLatencyTracker.earlyDumpRequestSubmittedWithSize(
+ mTempDumpedPids.size());
+ Future<File> firstPidDumpPromise = mEarlyDumpExecutor.submit(() -> {
+ // the class AnrLatencyTracker is not generally thread safe but the values
+ // recorded/touched by the Temporary dump thread(s) are all volatile/atomic.
+ File tracesFile = StackTracesDumpHelper.dumpStackTracesTempFile(incomingPid,
+ timeoutRecord.mLatencyTracker);
+ mTempDumpedPids.remove(incomingPid);
+ return tracesFile;
+ });
+
timeoutRecord.mLatencyTracker.anrRecordPlacingOnQueueWithSize(mAnrRecords.size());
mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
- parentShortComponentName, parentProcess, aboveSystem,
- mAuxiliaryTaskExecutor, timeoutRecord, isContinuousAnr));
+ parentShortComponentName, parentProcess, aboveSystem, timeoutRecord,
+ isContinuousAnr, firstPidDumpPromise));
}
startAnrConsumerIfNeeded();
} finally {
@@ -147,6 +182,16 @@
}
}
+ private static ThreadPoolExecutor makeExpiringThreadPoolWithSize(int size,
+ ThreadFactory factory) {
+ ThreadPoolExecutor pool = new ThreadPoolExecutor(/* corePoolSize= */ size,
+ /* maximumPoolSize= */ size, /* keepAliveTime= */ DEFAULT_THREAD_KEEP_ALIVE_SECOND,
+ TimeUnit.SECONDS, new LinkedBlockingQueue<>(), factory);
+ // We allow the core threads to expire after the keepAliveTime.
+ pool.allowCoreThreadTimeOut(true);
+ return pool;
+ }
+
/**
* The thread to execute {@link ProcessErrorStateRecord#appNotResponding}. It will terminate if
* all records are handled.
@@ -219,7 +264,7 @@
}
}
- private static class AnrRecord {
+ private class AnrRecord {
final ProcessRecord mApp;
final int mPid;
final String mActivityShortComponentName;
@@ -228,14 +273,14 @@
final ApplicationInfo mAppInfo;
final WindowProcessController mParentProcess;
final boolean mAboveSystem;
- final ExecutorService mAuxiliaryTaskExecutor;
final long mTimestamp = SystemClock.uptimeMillis();
final boolean mIsContinuousAnr;
+ final Future<File> mFirstPidFilePromise;
AnrRecord(ProcessRecord anrProcess, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem,
- ExecutorService auxiliaryTaskExecutor, TimeoutRecord timeoutRecord,
- boolean isContinuousAnr) {
+ TimeoutRecord timeoutRecord, boolean isContinuousAnr,
+ Future<File> firstPidFilePromise) {
mApp = anrProcess;
mPid = anrProcess.mPid;
mActivityShortComponentName = activityShortComponentName;
@@ -244,8 +289,8 @@
mAppInfo = aInfo;
mParentProcess = parentProcess;
mAboveSystem = aboveSystem;
- mAuxiliaryTaskExecutor = auxiliaryTaskExecutor;
mIsContinuousAnr = isContinuousAnr;
+ mFirstPidFilePromise = firstPidFilePromise;
}
void appNotResponding(boolean onlyDumpSelf) {
@@ -254,7 +299,7 @@
mApp.mErrorState.appNotResponding(mActivityShortComponentName, mAppInfo,
mParentShortComponentName, mParentProcess, mAboveSystem,
mTimeoutRecord, mAuxiliaryTaskExecutor, onlyDumpSelf,
- mIsContinuousAnr);
+ mIsContinuousAnr, mFirstPidFilePromise);
} finally {
mTimeoutRecord.mLatencyTracker.anrProcessingEnded();
}
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/ForegroundServiceTypeLoggerModule.java b/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java
index 993595b..8f84b08 100644
--- a/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java
+++ b/services/core/java/com/android/server/am/ForegroundServiceTypeLoggerModule.java
@@ -190,6 +190,10 @@
// and also clean up the start calls stack by UID
final ArrayList<Integer> apiTypes = convertFgsTypeToApiTypes(record.foregroundServiceType);
final UidState uidState = mUids.get(uid);
+ if (uidState == null) {
+ Log.e(TAG, "FGS stop call being logged with no start call for UID " + uid);
+ return;
+ }
final ArrayList<Integer> apisFound = new ArrayList<>();
final ArrayList<Long> timestampsFound = new ArrayList<>();
for (int i = 0, size = apiTypes.size(); i < size; i++) {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 365dcd9..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"})
@@ -1482,7 +1482,10 @@
}
if (uidRec.isIdle() && !uidRec.isSetIdle()) {
uidChange |= UidRecord.CHANGE_IDLE;
- becameIdle.add(uidRec);
+ if (uidRec.getSetProcState() != PROCESS_STATE_NONEXISTENT) {
+ // don't stop the bg services if it's just started.
+ becameIdle.add(uidRec);
+ }
}
} else {
if (uidRec.isIdle()) {
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index ca41f42..e498384 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -290,7 +290,7 @@
String parentShortComponentName, WindowProcessController parentProcess,
boolean aboveSystem, TimeoutRecord timeoutRecord,
ExecutorService auxiliaryTaskExecutor, boolean onlyDumpSelf,
- boolean isContinuousAnr) {
+ boolean isContinuousAnr, Future<File> firstPidFilePromise) {
String annotation = timeoutRecord.mReason;
AnrLatencyTracker latencyTracker = timeoutRecord.mLatencyTracker;
Future<?> updateCpuStatsNowFirstCall = null;
@@ -335,7 +335,6 @@
Counter.logIncrement("stability_anr.value_skipped_anrs");
return;
}
-
// In case we come through here for the same app before completing
// this one, mark as anring now so we will bail out.
latencyTracker.waitingOnProcLockStarted();
@@ -369,6 +368,9 @@
firstPids.add(pid);
// Don't dump other PIDs if it's a background ANR or is requested to only dump self.
+ // Note that the primary pid is added here just in case, as it should normally be
+ // dumped on the early dump thread, and would only be dumped on the Anr consumer thread
+ // as a fallback.
isSilentAnr = isSilentAnr();
if (!isSilentAnr && !onlyDumpSelf) {
int parentPid = pid;
@@ -501,7 +503,8 @@
File tracesFile = StackTracesDumpHelper.dumpStackTraces(firstPids,
isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids,
nativePidsFuture, tracesFileException, firstPidEndOffset, annotation,
- criticalEventLog, memoryHeaders, auxiliaryTaskExecutor, latencyTracker);
+ criticalEventLog, memoryHeaders, auxiliaryTaskExecutor, firstPidFilePromise,
+ latencyTracker);
if (isMonitorCpuUsage()) {
// Wait for the first call to finish
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/am/StackTracesDumpHelper.java b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
index 10ddc2f..01fb0d1 100644
--- a/services/core/java/com/android/server/am/StackTracesDumpHelper.java
+++ b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
@@ -41,6 +41,7 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -50,6 +51,8 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;
@@ -65,11 +68,16 @@
new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS");
static final String ANR_FILE_PREFIX = "anr_";
- public static final String ANR_TRACE_DIR = "/data/anr";
+ static final String ANR_TEMP_FILE_PREFIX = "temp_anr_";
+ public static final String ANR_TRACE_DIR = "/data/anr";
private static final int NATIVE_DUMP_TIMEOUT_MS =
2000 * Build.HW_TIMEOUT_MULTIPLIER; // 2 seconds;
private static final int JAVA_DUMP_MINIMUM_SIZE = 100; // 100 bytes.
+ // The time limit for a single process's dump
+ private static final int TEMP_DUMP_TIME_LIMIT =
+ 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; // 10 seconds
+
/**
* If a stack trace dump file is configured, dump process stack traces.
@@ -85,7 +93,7 @@
Future<ArrayList<Integer>> nativePidsFuture, StringWriter logExceptionCreatingFile,
@NonNull Executor auxiliaryTaskExecutor, AnrLatencyTracker latencyTracker) {
return dumpStackTraces(firstPids, processCpuTracker, lastPids, nativePidsFuture,
- logExceptionCreatingFile, null, null, null, null, auxiliaryTaskExecutor,
+ logExceptionCreatingFile, null, null, null, null, auxiliaryTaskExecutor, null,
latencyTracker);
}
@@ -96,11 +104,11 @@
public static File dumpStackTraces(ArrayList<Integer> firstPids,
ProcessCpuTracker processCpuTracker, SparseBooleanArray lastPids,
Future<ArrayList<Integer>> nativePidsFuture, StringWriter logExceptionCreatingFile,
- String subject, String criticalEventSection, @NonNull Executor auxiliaryTaskExecutor,
- AnrLatencyTracker latencyTracker) {
+ String subject, String criticalEventSection,
+ @NonNull Executor auxiliaryTaskExecutor, AnrLatencyTracker latencyTracker) {
return dumpStackTraces(firstPids, processCpuTracker, lastPids, nativePidsFuture,
logExceptionCreatingFile, null, subject, criticalEventSection,
- /* memoryHeaders= */ null, auxiliaryTaskExecutor, latencyTracker);
+ /* memoryHeaders= */ null, auxiliaryTaskExecutor, null, latencyTracker);
}
/**
@@ -112,7 +120,7 @@
Future<ArrayList<Integer>> nativePidsFuture, StringWriter logExceptionCreatingFile,
AtomicLong firstPidEndOffset, String subject, String criticalEventSection,
String memoryHeaders, @NonNull Executor auxiliaryTaskExecutor,
- AnrLatencyTracker latencyTracker) {
+ Future<File> firstPidFilePromise, AnrLatencyTracker latencyTracker) {
try {
if (latencyTracker != null) {
@@ -161,7 +169,7 @@
long firstPidEndPos = dumpStackTraces(
tracesFile.getAbsolutePath(), firstPids, nativePidsFuture,
- extraPidsFuture, latencyTracker);
+ extraPidsFuture, firstPidFilePromise, latencyTracker);
if (firstPidEndOffset != null) {
firstPidEndOffset.set(firstPidEndPos);
}
@@ -175,7 +183,6 @@
latencyTracker.dumpStackTracesEnded();
}
}
-
}
/**
@@ -183,7 +190,8 @@
*/
public static long dumpStackTraces(String tracesFile,
ArrayList<Integer> firstPids, Future<ArrayList<Integer>> nativePidsFuture,
- Future<ArrayList<Integer>> extraPidsFuture, AnrLatencyTracker latencyTracker) {
+ Future<ArrayList<Integer>> extraPidsFuture, Future<File> firstPidFilePromise,
+ AnrLatencyTracker latencyTracker) {
Slog.i(TAG, "Dumping to " + tracesFile);
@@ -194,33 +202,52 @@
// We must complete all stack dumps within 20 seconds.
long remainingTime = 20 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
- // As applications are usually interested with the ANR stack traces, but we can't share with
- // them the stack traces other than their own stacks. So after the very first PID is
+ // As applications are usually interested with the ANR stack traces, but we can't share
+ // with them the stack traces other than their own stacks. So after the very first PID is
// dumped, remember the current file size.
long firstPidEnd = -1;
- // First collect all of the stacks of the most important pids.
- if (firstPids != null) {
+ // Was the first pid copied from the temporary file that was created in the predump phase?
+ boolean firstPidTempDumpCopied = false;
+
+ // First copy the first pid's dump from the temporary file it was dumped into earlier,
+ // The first pid should always exist in firstPids but we check the size just in case.
+ if (firstPidFilePromise != null && firstPids != null && firstPids.size() > 0) {
+ final int primaryPid = firstPids.get(0);
+ final long start = SystemClock.elapsedRealtime();
+ firstPidTempDumpCopied = copyFirstPidTempDump(tracesFile, firstPidFilePromise,
+ remainingTime, latencyTracker);
+ final long timeTaken = SystemClock.elapsedRealtime() - start;
+ remainingTime -= timeTaken;
+ if (remainingTime <= 0) {
+ Slog.e(TAG, "Aborting stack trace dump (currently copying primary pid" + primaryPid
+ + "); deadline exceeded.");
+ return firstPidEnd;
+ }
+ // We don't copy ANR traces from the system_server intentionally.
+ if (firstPidTempDumpCopied && primaryPid != ActivityManagerService.MY_PID) {
+ firstPidEnd = new File(tracesFile).length();
+ }
+ // Append the Durations/latency comma separated array after the first PID.
+ if (latencyTracker != null) {
+ appendtoANRFile(tracesFile,
+ latencyTracker.dumpAsCommaSeparatedArrayWithHeader());
+ }
+ }
+ // Next collect all of the stacks of the most important pids.
+ if (firstPids != null) {
if (latencyTracker != null) {
latencyTracker.dumpingFirstPidsStarted();
}
int num = firstPids.size();
- for (int i = 0; i < num; i++) {
+ for (int i = firstPidTempDumpCopied ? 1 : 0; i < num; i++) {
final int pid = firstPids.get(i);
// We don't copy ANR traces from the system_server intentionally.
final boolean firstPid = i == 0 && ActivityManagerService.MY_PID != pid;
- if (latencyTracker != null) {
- latencyTracker.dumpingPidStarted(pid);
- }
-
Slog.i(TAG, "Collecting stacks for pid " + pid);
- final long timeTaken = dumpJavaTracesTombstoned(pid, tracesFile,
- remainingTime);
- if (latencyTracker != null) {
- latencyTracker.dumpingPidEnded();
- }
-
+ final long timeTaken = dumpJavaTracesTombstoned(pid, tracesFile, remainingTime,
+ latencyTracker);
remainingTime -= timeTaken;
if (remainingTime <= 0) {
Slog.e(TAG, "Aborting stack trace dump (current firstPid=" + pid
@@ -304,13 +331,8 @@
}
for (int pid : extraPids) {
Slog.i(TAG, "Collecting stacks for extra pid " + pid);
- if (latencyTracker != null) {
- latencyTracker.dumpingPidStarted(pid);
- }
- final long timeTaken = dumpJavaTracesTombstoned(pid, tracesFile, remainingTime);
- if (latencyTracker != null) {
- latencyTracker.dumpingPidEnded();
- }
+ final long timeTaken = dumpJavaTracesTombstoned(pid, tracesFile, remainingTime,
+ latencyTracker);
remainingTime -= timeTaken;
if (remainingTime <= 0) {
Slog.e(TAG, "Aborting stack trace dump (current extra pid=" + pid
@@ -333,6 +355,99 @@
return firstPidEnd;
}
+ /**
+ * Dumps the supplied pid to a temporary file.
+ * @param pid the PID to be dumped
+ * @param latencyTracker the latency tracker instance of the current ANR.
+ */
+ public static File dumpStackTracesTempFile(int pid, AnrLatencyTracker latencyTracker) {
+ try {
+ if (latencyTracker != null) {
+ latencyTracker.dumpStackTracesTempFileStarted();
+ }
+
+ File tmpTracesFile;
+ try {
+ tmpTracesFile = File.createTempFile(ANR_TEMP_FILE_PREFIX, ".txt",
+ new File(ANR_TRACE_DIR));
+ Slog.d(TAG, "created ANR temporary file:" + tmpTracesFile.getAbsolutePath());
+ } catch (IOException e) {
+ Slog.w(TAG, "Exception creating temporary ANR dump file:", e);
+ if (latencyTracker != null) {
+ latencyTracker.dumpStackTracesTempFileCreationFailed();
+ }
+ return null;
+ }
+
+ Slog.i(TAG, "Collecting stacks for pid " + pid + " into temporary file "
+ + tmpTracesFile.getName());
+ if (latencyTracker != null) {
+ latencyTracker.dumpingPidStarted(pid);
+ }
+ final long timeTaken = dumpJavaTracesTombstoned(pid, tmpTracesFile.getAbsolutePath(),
+ TEMP_DUMP_TIME_LIMIT);
+ if (latencyTracker != null) {
+ latencyTracker.dumpingPidEnded();
+ }
+ if (TEMP_DUMP_TIME_LIMIT <= timeTaken) {
+ Slog.e(TAG, "Aborted stack trace dump (current primary pid=" + pid
+ + "); deadline exceeded.");
+ tmpTracesFile.delete();
+ if (latencyTracker != null) {
+ latencyTracker.dumpStackTracesTempFileTimedOut();
+ }
+ return null;
+ }
+ if (DEBUG_ANR) {
+ Slog.d(TAG, "Done with primary pid " + pid + " in " + timeTaken + "ms"
+ + " dumped into temporary file " + tmpTracesFile.getName());
+ }
+ return tmpTracesFile;
+ } finally {
+ if (latencyTracker != null) {
+ latencyTracker.dumpStackTracesTempFileEnded();
+ }
+ }
+ }
+
+ private static boolean copyFirstPidTempDump(String tracesFile, Future<File> firstPidFilePromise,
+ long timeLimitMs, AnrLatencyTracker latencyTracker) {
+
+ boolean copySucceeded = false;
+ try (FileOutputStream fos = new FileOutputStream(tracesFile, true)) {
+ if (latencyTracker != null) {
+ latencyTracker.copyingFirstPidStarted();
+ }
+ final File tempfile = firstPidFilePromise.get(timeLimitMs, TimeUnit.MILLISECONDS);
+ if (tempfile != null) {
+ Files.copy(tempfile.toPath(), fos);
+ // Delete the temporary first pid dump file
+ tempfile.delete();
+ copySucceeded = true;
+ return copySucceeded;
+ }
+ return false;
+ } catch (ExecutionException e) {
+ Slog.w(TAG, "Failed to collect the first pid's predump to the main ANR file",
+ e.getCause());
+ return false;
+ } catch (InterruptedException e) {
+ Slog.w(TAG, "Interrupted while collecting the first pid's predump"
+ + " to the main ANR file", e);
+ return false;
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to read the first pid's predump file", e);
+ return false;
+ } catch (TimeoutException e) {
+ Slog.w(TAG, "Copying the first pid timed out", e);
+ return false;
+ } finally {
+ if (latencyTracker != null) {
+ latencyTracker.copyingFirstPidEnded(copySucceeded);
+ }
+ }
+ }
+
private static synchronized File createAnrDumpFile(File tracesDir) throws IOException {
final String formattedDate = ANR_FILE_DATE_FORMAT.format(new Date());
final File anrFile = new File(tracesDir, ANR_FILE_PREFIX + formattedDate);
@@ -409,6 +524,21 @@
Slog.w(TAG, "tombstone modification times changed while sorting; not pruning", e);
}
}
+
+ private static long dumpJavaTracesTombstoned(int pid, String fileName, long timeoutMs,
+ AnrLatencyTracker latencyTracker) {
+ try {
+ if (latencyTracker != null) {
+ latencyTracker.dumpingPidStarted(pid);
+ }
+ return dumpJavaTracesTombstoned(pid, fileName, timeoutMs);
+ } finally {
+ if (latencyTracker != null) {
+ latencyTracker.dumpingPidEnded();
+ }
+ }
+ }
+
/**
* Dump java traces for process {@code pid} to the specified file. If java trace dumping
* fails, a native backtrace is attempted. Note that the timeout {@code timeoutMs} only applies
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 462942e..2da9fa6 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -87,14 +87,14 @@
private final @NonNull Context mContext;
/** ID for Communication strategy retrieved form audio policy manager */
- /*package*/ int mCommunicationStrategyId = -1;
+ private int mCommunicationStrategyId = -1;
/** ID for Accessibility strategy retrieved form audio policy manager */
private int mAccessibilityStrategyId = -1;
/** Active communication device reported by audio policy manager */
- /*package*/ AudioDeviceInfo mActiveCommunicationDevice;
+ private AudioDeviceInfo mActiveCommunicationDevice;
/** Last preferred device set for communication strategy */
private AudioDeviceAttributes mPreferredCommunicationDevice;
@@ -750,19 +750,6 @@
mIsLeOutput = false;
}
- BtDeviceInfo(@NonNull BtDeviceInfo src, int state) {
- mDevice = src.mDevice;
- mState = state;
- mProfile = src.mProfile;
- mSupprNoisy = src.mSupprNoisy;
- mVolume = src.mVolume;
- mIsLeOutput = src.mIsLeOutput;
- mEventSource = src.mEventSource;
- mAudioSystemDevice = src.mAudioSystemDevice;
- mMusicDevice = src.mMusicDevice;
- mCodec = src.mCodec;
- }
-
// redefine equality op so we can match messages intended for this device
@Override
public boolean equals(Object o) {
@@ -829,7 +816,7 @@
* @param info struct with the (dis)connection information
*/
/*package*/ void queueOnBluetoothActiveDeviceChanged(@NonNull BtDeviceChangedData data) {
- if (data.mPreviousDevice != null
+ if (data.mInfo.getProfile() == BluetoothProfile.A2DP && data.mPreviousDevice != null
&& data.mPreviousDevice.equals(data.mNewDevice)) {
final String name = TextUtils.emptyIfNull(data.mNewDevice.getName());
new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
@@ -838,8 +825,7 @@
.set(MediaMetrics.Property.STATUS, data.mInfo.getProfile())
.record();
synchronized (mDeviceStateLock) {
- postBluetoothDeviceConfigChange(createBtDeviceInfo(data, data.mNewDevice,
- BluetoothProfile.STATE_CONNECTED));
+ postBluetoothA2dpDeviceConfigChange(data.mNewDevice);
}
} else {
synchronized (mDeviceStateLock) {
@@ -1064,8 +1050,8 @@
new AudioModeInfo(mode, pid, uid));
}
- /*package*/ void postBluetoothDeviceConfigChange(@NonNull BtDeviceInfo info) {
- sendLMsgNoDelay(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, info);
+ /*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) {
+ sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, device);
}
/*package*/ void startBluetoothScoForClient(IBinder cb, int pid, int scoAudioMode,
@@ -1322,10 +1308,6 @@
sendIMsgNoDelay(MSG_I_SCO_AUDIO_STATE_CHANGED, SENDMSG_QUEUE, state);
}
- /*package*/ void postNotifyPreferredAudioProfileApplied(BluetoothDevice btDevice) {
- sendLMsgNoDelay(MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED, SENDMSG_QUEUE, btDevice);
- }
-
/*package*/ static final class CommunicationDeviceInfo {
final @NonNull IBinder mCb; // Identifies the requesting client for death handler
final int mPid; // Requester process ID
@@ -1401,11 +1383,9 @@
}
}
- /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes,
- boolean connect, @Nullable BluetoothDevice btDevice) {
+ /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect) {
synchronized (mDeviceStateLock) {
- return mDeviceInventory.handleDeviceConnection(
- attributes, connect, false /*for test*/, btDevice);
+ return mDeviceInventory.handleDeviceConnection(attributes, connect, false /*for test*/);
}
}
@@ -1646,10 +1626,13 @@
(String) msg.obj, msg.arg1);
}
break;
- case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE:
+ case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
+ final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
synchronized (mDeviceStateLock) {
- mDeviceInventory.onBluetoothDeviceConfigChange(
- (BtDeviceInfo) msg.obj, BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
+ final int a2dpCodec = mBtHelper.getA2dpCodec(btDevice);
+ mDeviceInventory.onBluetoothA2dpDeviceConfigChange(
+ new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec),
+ BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
}
break;
case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
@@ -1807,10 +1790,6 @@
final int capturePreset = msg.arg1;
mDeviceInventory.onSaveClearPreferredDevicesForCapturePreset(capturePreset);
} break;
- case MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED: {
- final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
- BtHelper.onNotifyPreferredAudioProfileApplied(btDevice);
- } break;
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -1846,7 +1825,7 @@
private static final int MSG_IL_BTA2DP_TIMEOUT = 10;
// process change of A2DP device configuration, obj is BluetoothDevice
- private static final int MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE = 11;
+ private static final int MSG_L_A2DP_DEVICE_CONFIG_CHANGE = 11;
private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 12;
private static final int MSG_REPORT_NEW_ROUTES = 13;
@@ -1886,15 +1865,13 @@
private static final int MSG_IL_SAVE_REMOVE_NDEF_DEVICE_FOR_STRATEGY = 48;
private static final int MSG_IL_BTLEAUDIO_TIMEOUT = 49;
- private static final int MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED = 50;
-
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
case MSG_L_SET_BT_ACTIVE_DEVICE:
case MSG_IL_BTA2DP_TIMEOUT:
case MSG_IL_BTLEAUDIO_TIMEOUT:
- case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE:
+ case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
case MSG_TOGGLE_HDMI:
case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT:
case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
@@ -1986,7 +1963,7 @@
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
case MSG_IL_BTA2DP_TIMEOUT:
case MSG_IL_BTLEAUDIO_TIMEOUT:
- case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE:
+ case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
if (sLastDeviceConnectMsgTime >= time) {
// add a little delay to make sure messages are ordered as expected
time = sLastDeviceConnectMsgTime + 30;
@@ -2006,7 +1983,7 @@
static {
MESSAGES_MUTE_MUSIC = new HashSet<>();
MESSAGES_MUTE_MUSIC.add(MSG_L_SET_BT_ACTIVE_DEVICE);
- MESSAGES_MUTE_MUSIC.add(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE);
+ MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE);
MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT);
MESSAGES_MUTE_MUSIC.add(MSG_IIL_SET_FORCE_BT_A2DP_USE);
}
@@ -2027,7 +2004,7 @@
// Do not mute on bluetooth event if music is playing on a wired headset.
if ((message == MSG_L_SET_BT_ACTIVE_DEVICE
|| message == MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT
- || message == MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE)
+ || message == MSG_L_A2DP_DEVICE_CONFIG_CHANGE)
&& AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)
&& hasIntersection(mDeviceInventory.DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET,
mAudioService.getDeviceSetForStream(AudioSystem.STREAM_MUSIC))) {
@@ -2166,19 +2143,18 @@
if (preferredCommunicationDevice == null) {
AudioDeviceAttributes defaultDevice = getDefaultCommunicationDevice();
if (defaultDevice != null) {
- mDeviceInventory.setPreferredDevicesForStrategy(
+ setPreferredDevicesForStrategySync(
mCommunicationStrategyId, Arrays.asList(defaultDevice));
- mDeviceInventory.setPreferredDevicesForStrategy(
+ setPreferredDevicesForStrategySync(
mAccessibilityStrategyId, Arrays.asList(defaultDevice));
} else {
- mDeviceInventory.removePreferredDevicesForStrategy(mCommunicationStrategyId);
- mDeviceInventory.removePreferredDevicesForStrategy(mAccessibilityStrategyId);
+ removePreferredDevicesForStrategySync(mCommunicationStrategyId);
+ removePreferredDevicesForStrategySync(mAccessibilityStrategyId);
}
- mDeviceInventory.applyConnectedDevicesRoles();
} else {
- mDeviceInventory.setPreferredDevicesForStrategy(
+ setPreferredDevicesForStrategySync(
mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
- mDeviceInventory.setPreferredDevicesForStrategy(
+ setPreferredDevicesForStrategySync(
mAccessibilityStrategyId, Arrays.asList(preferredCommunicationDevice));
}
onUpdatePhoneStrategyDevice(preferredCommunicationDevice);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 1eb39f7..228bc87 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -34,36 +34,26 @@
import android.media.IStrategyNonDefaultDevicesDispatcher;
import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.MediaMetrics;
-import android.media.MediaRecorder.AudioSource;
-import android.media.audiopolicy.AudioProductStrategy;
import android.media.permission.ClearCallingIdentityContext;
import android.media.permission.SafeCloseable;
import android.os.Binder;
-import android.os.Bundle;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
-import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.utils.EventLogger;
-import com.google.android.collect.Sets;
-
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
@@ -185,26 +175,18 @@
final RemoteCallbackList<ICapturePresetDevicesRoleDispatcher> mDevRoleCapturePresetDispatchers =
new RemoteCallbackList<ICapturePresetDevicesRoleDispatcher>();
- final List<AudioProductStrategy> mStrategies;
-
/*package*/ AudioDeviceInventory(@NonNull AudioDeviceBroker broker) {
- this(broker, AudioSystemAdapter.getDefaultAdapter());
+ mDeviceBroker = broker;
+ mAudioSystem = AudioSystemAdapter.getDefaultAdapter();
}
//-----------------------------------------------------------
/** for mocking only, allows to inject AudioSystem adapter */
/*package*/ AudioDeviceInventory(@NonNull AudioSystemAdapter audioSystem) {
- this(null, audioSystem);
+ mDeviceBroker = null;
+ mAudioSystem = audioSystem;
}
- private AudioDeviceInventory(@Nullable AudioDeviceBroker broker,
- @Nullable AudioSystemAdapter audioSystem) {
- mDeviceBroker = broker;
- mAudioSystem = audioSystem;
- mStrategies = AudioProductStrategy.getAudioProductStrategies();
- mBluetoothDualModeEnabled = SystemProperties.getBoolean(
- "persist.bluetooth.enable_dual_mode_audio", false);
- }
/*package*/ void setDeviceBroker(@NonNull AudioDeviceBroker broker) {
mDeviceBroker = broker;
}
@@ -221,13 +203,8 @@
int mDeviceCodecFormat;
final UUID mSensorUuid;
- /** Disabled operating modes for this device. Use a negative logic so that by default
- * an empty list means all modes are allowed.
- * See BluetoothAdapter.AUDIO_MODE_DUPLEX and BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY */
- @NonNull ArraySet<String> mDisabledModes = new ArraySet(0);
-
DeviceInfo(int deviceType, String deviceName, String deviceAddress,
- int deviceCodecFormat, @Nullable UUID sensorUuid) {
+ int deviceCodecFormat, UUID sensorUuid) {
mDeviceType = deviceType;
mDeviceName = deviceName == null ? "" : deviceName;
mDeviceAddress = deviceAddress == null ? "" : deviceAddress;
@@ -235,31 +212,11 @@
mSensorUuid = sensorUuid;
}
- void setModeDisabled(String mode) {
- mDisabledModes.add(mode);
- }
- void setModeEnabled(String mode) {
- mDisabledModes.remove(mode);
- }
- boolean isModeEnabled(String mode) {
- return !mDisabledModes.contains(mode);
- }
- boolean isOutputOnlyModeEnabled() {
- return isModeEnabled(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY);
- }
- boolean isDuplexModeEnabled() {
- return isModeEnabled(BluetoothAdapter.AUDIO_MODE_DUPLEX);
- }
-
DeviceInfo(int deviceType, String deviceName, String deviceAddress,
int deviceCodecFormat) {
this(deviceType, deviceName, deviceAddress, deviceCodecFormat, null);
}
- DeviceInfo(int deviceType, String deviceName, String deviceAddress) {
- this(deviceType, deviceName, deviceAddress, AudioSystem.AUDIO_FORMAT_DEFAULT);
- }
-
@Override
public String toString() {
return "[DeviceInfo: type:0x" + Integer.toHexString(mDeviceType)
@@ -267,8 +224,7 @@
+ ") name:" + mDeviceName
+ " addr:" + mDeviceAddress
+ " codec: " + Integer.toHexString(mDeviceCodecFormat)
- + " sensorUuid: " + Objects.toString(mSensorUuid)
- + " disabled modes: " + mDisabledModes + "]";
+ + " sensorUuid: " + Objects.toString(mSensorUuid) + "]";
}
@NonNull String getKey() {
@@ -320,18 +276,9 @@
pw.println(" " + prefix + " type:0x" + Integer.toHexString(keyType)
+ " (" + AudioSystem.getDeviceName(keyType)
+ ") addr:" + valueAddress); });
- pw.println("\n" + prefix + "Preferred devices for capture preset:");
mPreferredDevicesForCapturePreset.forEach((capturePreset, devices) -> {
pw.println(" " + prefix + "capturePreset:" + capturePreset
+ " devices:" + devices); });
- pw.println("\n" + prefix + "Applied devices roles for strategies:");
- mAppliedStrategyRoles.forEach((key, devices) -> {
- pw.println(" " + prefix + "strategy: " + key.first
- + " role:" + key.second + " devices:" + devices); });
- pw.println("\n" + prefix + "Applied devices roles for presets:");
- mAppliedPresetRoles.forEach((key, devices) -> {
- pw.println(" " + prefix + "preset: " + key.first
- + " role:" + key.second + " devices:" + devices); });
}
//------------------------------------------------------------
@@ -352,16 +299,15 @@
AudioSystem.DEVICE_STATE_AVAILABLE,
di.mDeviceCodecFormat);
}
- mAppliedStrategyRoles.clear();
- applyConnectedDevicesRoles_l();
}
synchronized (mPreferredDevices) {
mPreferredDevices.forEach((strategy, devices) -> {
- setPreferredDevicesForStrategy(strategy, devices); });
+ mAudioSystem.setDevicesRoleForStrategy(
+ strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); });
}
synchronized (mNonDefaultDevices) {
mNonDefaultDevices.forEach((strategy, devices) -> {
- addDevicesRoleForStrategy(
+ mAudioSystem.setDevicesRoleForStrategy(
strategy, AudioSystem.DEVICE_ROLE_DISABLED, devices); });
}
synchronized (mPreferredDevicesForCapturePreset) {
@@ -434,7 +380,8 @@
btInfo.mVolume * 10, btInfo.mAudioSystemDevice,
"onSetBtActiveDevice");
}
- makeA2dpDeviceAvailable(btInfo, "onSetBtActiveDevice");
+ makeA2dpDeviceAvailable(address, BtHelper.getName(btInfo.mDevice),
+ "onSetBtActiveDevice", btInfo.mCodec);
}
break;
case BluetoothProfile.HEARING_AID:
@@ -450,7 +397,10 @@
if (switchToUnavailable) {
makeLeAudioDeviceUnavailableNow(address, btInfo.mAudioSystemDevice);
} else if (switchToAvailable) {
- makeLeAudioDeviceAvailable(btInfo, streamType, "onSetBtActiveDevice");
+ makeLeAudioDeviceAvailable(address, BtHelper.getName(btInfo.mDevice),
+ streamType, btInfo.mVolume == -1 ? -1 : btInfo.mVolume * 10,
+ btInfo.mAudioSystemDevice,
+ "onSetBtActiveDevice");
}
break;
default: throw new IllegalArgumentException("Invalid profile "
@@ -461,30 +411,30 @@
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
- /*package*/ void onBluetoothDeviceConfigChange(
- @NonNull AudioDeviceBroker.BtDeviceInfo btInfo, int event) {
+ /*package*/ void onBluetoothA2dpDeviceConfigChange(
+ @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int event) {
MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId
- + "onBluetoothDeviceConfigChange")
- .set(MediaMetrics.Property.EVENT, BtHelper.deviceEventToString(event));
+ + "onBluetoothA2dpDeviceConfigChange")
+ .set(MediaMetrics.Property.EVENT, BtHelper.a2dpDeviceEventToString(event));
- final BluetoothDevice btDevice = btInfo.mDevice;
+ final BluetoothDevice btDevice = btInfo.getBtDevice();
if (btDevice == null) {
mmi.set(MediaMetrics.Property.EARLY_RETURN, "btDevice null").record();
return;
}
if (AudioService.DEBUG_DEVICES) {
- Log.d(TAG, "onBluetoothDeviceConfigChange btDevice=" + btDevice);
+ Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
}
- int volume = btInfo.mVolume;
- @AudioSystem.AudioFormatNativeEnumForBtCodec final int audioCodec = btInfo.mCodec;
+ int a2dpVolume = btInfo.getVolume();
+ @AudioSystem.AudioFormatNativeEnumForBtCodec final int a2dpCodec = btInfo.getCodec();
String address = btDevice.getAddress();
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
address = "";
}
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
- "onBluetoothDeviceConfigChange addr=" + address
- + " event=" + BtHelper.deviceEventToString(event)));
+ "onBluetoothA2dpDeviceConfigChange addr=" + address
+ + " event=" + BtHelper.a2dpDeviceEventToString(event)));
synchronized (mDevicesLock) {
if (mDeviceBroker.hasScheduledA2dpConnection(btDevice)) {
@@ -499,55 +449,54 @@
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
final DeviceInfo di = mConnectedDevices.get(key);
if (di == null) {
- Log.e(TAG, "invalid null DeviceInfo in onBluetoothDeviceConfigChange");
+ Log.e(TAG, "invalid null DeviceInfo in onBluetoothA2dpDeviceConfigChange");
mmi.set(MediaMetrics.Property.EARLY_RETURN, "null DeviceInfo").record();
return;
}
mmi.set(MediaMetrics.Property.ADDRESS, address)
.set(MediaMetrics.Property.ENCODING,
- AudioSystem.audioFormatToString(audioCodec))
- .set(MediaMetrics.Property.INDEX, volume)
+ AudioSystem.audioFormatToString(a2dpCodec))
+ .set(MediaMetrics.Property.INDEX, a2dpVolume)
.set(MediaMetrics.Property.NAME, di.mDeviceName);
-
- if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
- boolean a2dpCodecChange = false;
- if (btInfo.mProfile == BluetoothProfile.A2DP) {
- if (di.mDeviceCodecFormat != audioCodec) {
- di.mDeviceCodecFormat = audioCodec;
- mConnectedDevices.replace(key, di);
- a2dpCodecChange = true;
- }
- final int res = mAudioSystem.handleDeviceConfigChange(
- btInfo.mAudioSystemDevice, address,
- BtHelper.getName(btDevice), audioCodec);
-
- if (res != AudioSystem.AUDIO_STATUS_OK) {
- AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
- "APM handleDeviceConfigChange failed for A2DP device addr="
- + address + " codec="
- + AudioSystem.audioFormatToString(audioCodec))
- .printLog(TAG));
-
- // force A2DP device disconnection in case of error so that AudioService
- // state is consistent with audio policy manager state
- setBluetoothActiveDevice(new AudioDeviceBroker.BtDeviceInfo(btInfo,
- BluetoothProfile.STATE_DISCONNECTED));
- } else {
- AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
- "APM handleDeviceConfigChange success for A2DP device addr="
- + address
- + " codec=" + AudioSystem.audioFormatToString(audioCodec))
- .printLog(TAG));
-
- }
+ if (event == BtHelper.EVENT_ACTIVE_DEVICE_CHANGE) {
+ // Device is connected
+ if (a2dpVolume != -1) {
+ mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
+ // convert index to internal representation in VolumeStreamState
+ a2dpVolume * 10,
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+ "onBluetoothA2dpDeviceConfigChange");
}
- if (!a2dpCodecChange) {
- updateBluetoothPreferredModes_l();
- mDeviceBroker.postNotifyPreferredAudioProfileApplied(btDevice);
+ } else if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
+ if (di.mDeviceCodecFormat != a2dpCodec) {
+ di.mDeviceCodecFormat = a2dpCodec;
+ mConnectedDevices.replace(key, di);
}
}
+ final int res = mAudioSystem.handleDeviceConfigChange(
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address,
+ BtHelper.getName(btDevice), a2dpCodec);
+
+ if (res != AudioSystem.AUDIO_STATUS_OK) {
+ AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "APM handleDeviceConfigChange failed for A2DP device addr=" + address
+ + " codec=" + AudioSystem.audioFormatToString(a2dpCodec))
+ .printLog(TAG));
+
+ int musicDevice = mDeviceBroker.getDeviceForStream(AudioSystem.STREAM_MUSIC);
+ // force A2DP device disconnection in case of error so that AudioService state is
+ // consistent with audio policy manager state
+ setBluetoothActiveDevice(new AudioDeviceBroker.BtDeviceInfo(btDevice,
+ BluetoothProfile.A2DP, BluetoothProfile.STATE_DISCONNECTED,
+ musicDevice, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
+ } else {
+ AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "APM handleDeviceConfigChange success for A2DP device addr=" + address
+ + " codec=" + AudioSystem.audioFormatToString(a2dpCodec))
+ .printLog(TAG));
+ }
}
mmi.record();
}
@@ -629,7 +578,7 @@
}
if (!handleDeviceConnection(wdcs.mAttributes,
- wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest, null)) {
+ wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest)) {
// change of connection state failed, bailout
mmi.set(MediaMetrics.Property.EARLY_RETURN, "change of connection state failed")
.record();
@@ -763,35 +712,23 @@
/*package*/ int setPreferredDevicesForStrategySync(int strategy,
@NonNull List<AudioDeviceAttributes> devices) {
- final int status = setPreferredDevicesForStrategy(strategy, devices);
+ int status = AudioSystem.ERROR;
+
+ try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
+ AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
+ "setPreferredDevicesForStrategySync, strategy: " + strategy
+ + " devices: " + devices)).printLog(TAG));
+ status = mAudioSystem.setDevicesRoleForStrategy(
+ strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
+ }
+
if (status == AudioSystem.SUCCESS) {
mDeviceBroker.postSaveSetPreferredDevicesForStrategy(strategy, devices);
}
return status;
}
- /*package*/ int setPreferredDevicesForStrategy(int strategy,
- @NonNull List<AudioDeviceAttributes> devices) {
- int status = AudioSystem.ERROR;
- try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
- AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
- "setPreferredDevicesForStrategy, strategy: " + strategy
- + " devices: " + devices)).printLog(TAG));
- status = setDevicesRoleForStrategy(
- strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
- }
- return status;
- }
-
/*package*/ int removePreferredDevicesForStrategySync(int strategy) {
- final int status = removePreferredDevicesForStrategy(strategy);
- if (status == AudioSystem.SUCCESS) {
- mDeviceBroker.postSaveRemovePreferredDevicesForStrategy(strategy);
- }
- return status;
- }
-
- /*package*/ int removePreferredDevicesForStrategy(int strategy) {
int status = AudioSystem.ERROR;
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
@@ -799,9 +736,13 @@
"removePreferredDevicesForStrategySync, strategy: "
+ strategy)).printLog(TAG));
- status = clearDevicesRoleForStrategy(
+ status = mAudioSystem.clearDevicesRoleForStrategy(
strategy, AudioSystem.DEVICE_ROLE_PREFERRED);
}
+
+ if (status == AudioSystem.SUCCESS) {
+ mDeviceBroker.postSaveRemovePreferredDevicesForStrategy(strategy);
+ }
return status;
}
@@ -816,7 +757,7 @@
AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
"setDeviceAsNonDefaultForStrategySync, strategy: " + strategy
+ " device: " + device)).printLog(TAG));
- status = addDevicesRoleForStrategy(
+ status = mAudioSystem.setDevicesRoleForStrategy(
strategy, AudioSystem.DEVICE_ROLE_DISABLED, devices);
}
@@ -838,7 +779,7 @@
"removeDeviceAsNonDefaultForStrategySync, strategy: "
+ strategy + " devices: " + device)).printLog(TAG));
- status = removeDevicesRoleForStrategy(
+ status = mAudioSystem.removeDevicesRoleForStrategy(
strategy, AudioSystem.DEVICE_ROLE_DISABLED, devices);
}
@@ -871,70 +812,33 @@
/*package*/ int setPreferredDevicesForCapturePresetSync(
int capturePreset, @NonNull List<AudioDeviceAttributes> devices) {
- final int status = setPreferredDevicesForCapturePreset(capturePreset, devices);
+ int status = AudioSystem.ERROR;
+
+ try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
+ status = mAudioSystem.setDevicesRoleForCapturePreset(
+ capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
+ }
+
if (status == AudioSystem.SUCCESS) {
mDeviceBroker.postSaveSetPreferredDevicesForCapturePreset(capturePreset, devices);
}
return status;
}
- private int setPreferredDevicesForCapturePreset(
- int capturePreset, @NonNull List<AudioDeviceAttributes> devices) {
- int status = AudioSystem.ERROR;
- try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
- status = setDevicesRoleForCapturePreset(
- capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
- }
- return status;
- }
-
/*package*/ int clearPreferredDevicesForCapturePresetSync(int capturePreset) {
- final int status = clearPreferredDevicesForCapturePreset(capturePreset);
+ int status = AudioSystem.ERROR;
+
+ try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
+ status = mAudioSystem.clearDevicesRoleForCapturePreset(
+ capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED);
+ }
+
if (status == AudioSystem.SUCCESS) {
mDeviceBroker.postSaveClearPreferredDevicesForCapturePreset(capturePreset);
}
return status;
}
- private int clearPreferredDevicesForCapturePreset(int capturePreset) {
- int status = AudioSystem.ERROR;
-
- try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
- status = clearDevicesRoleForCapturePreset(
- capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED);
- }
- return status;
- }
-
- private int addDevicesRoleForCapturePreset(int capturePreset, int role,
- @NonNull List<AudioDeviceAttributes> devices) {
- return addDevicesRole(mAppliedPresetRoles, (p, r, d) -> {
- return mAudioSystem.addDevicesRoleForCapturePreset(p, r, d);
- }, capturePreset, role, devices);
- }
-
- private int removeDevicesRoleForCapturePreset(int capturePreset, int role,
- @NonNull List<AudioDeviceAttributes> devices) {
- return removeDevicesRole(mAppliedPresetRoles, (p, r, d) -> {
- return mAudioSystem.removeDevicesRoleForCapturePreset(p, r, d);
- }, capturePreset, role, devices);
- }
-
- private int setDevicesRoleForCapturePreset(int capturePreset, int role,
- @NonNull List<AudioDeviceAttributes> devices) {
- return setDevicesRole(mAppliedPresetRoles, (p, r, d) -> {
- return mAudioSystem.addDevicesRoleForCapturePreset(p, r, d);
- }, (p, r, d) -> {
- return mAudioSystem.clearDevicesRoleForCapturePreset(p, r);
- }, capturePreset, role, devices);
- }
-
- private int clearDevicesRoleForCapturePreset(int capturePreset, int role) {
- return clearDevicesRole(mAppliedPresetRoles, (p, r, d) -> {
- return mAudioSystem.clearDevicesRoleForCapturePreset(p, r);
- }, capturePreset, role);
- }
-
/*package*/ void registerCapturePresetDevicesRoleDispatcher(
@NonNull ICapturePresetDevicesRoleDispatcher dispatcher) {
mDevRoleCapturePresetDispatchers.register(dispatcher);
@@ -945,208 +849,7 @@
mDevRoleCapturePresetDispatchers.unregister(dispatcher);
}
- private int addDevicesRoleForStrategy(int strategy, int role,
- @NonNull List<AudioDeviceAttributes> devices) {
- return addDevicesRole(mAppliedStrategyRoles, (s, r, d) -> {
- return mAudioSystem.setDevicesRoleForStrategy(s, r, d);
- }, strategy, role, devices);
- }
-
- private int removeDevicesRoleForStrategy(int strategy, int role,
- @NonNull List<AudioDeviceAttributes> devices) {
- return removeDevicesRole(mAppliedStrategyRoles, (s, r, d) -> {
- return mAudioSystem.removeDevicesRoleForStrategy(s, r, d);
- }, strategy, role, devices);
- }
-
- private int setDevicesRoleForStrategy(int strategy, int role,
- @NonNull List<AudioDeviceAttributes> devices) {
- return setDevicesRole(mAppliedStrategyRoles, (s, r, d) -> {
- return mAudioSystem.setDevicesRoleForStrategy(s, r, d);
- }, (s, r, d) -> {
- return mAudioSystem.clearDevicesRoleForStrategy(s, r);
- }, strategy, role, devices);
- }
-
- private int clearDevicesRoleForStrategy(int strategy, int role) {
- return clearDevicesRole(mAppliedStrategyRoles, (s, r, d) -> {
- return mAudioSystem.clearDevicesRoleForStrategy(s, r);
- }, strategy, role);
- }
-
- //------------------------------------------------------------
- // Cache for applied roles for strategies and devices. The cache avoids reapplying the
- // same list of devices for a given role and strategy and the corresponding systematic
- // redundant work in audio policy manager and audio flinger.
- // The key is the pair <Strategy , Role> and the value is the current list of devices.
-
- private final ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>>
- mAppliedStrategyRoles = new ArrayMap<>();
-
- // Cache for applied roles for capture presets and devices. The cache avoids reapplying the
- // same list of devices for a given role and capture preset and the corresponding systematic
- // redundant work in audio policy manager and audio flinger.
- // The key is the pair <Preset , Role> and the value is the current list of devices.
- private final ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>>
- mAppliedPresetRoles = new ArrayMap<>();
-
- interface AudioSystemInterface {
- int deviceRoleAction(int usecase, int role, @Nullable List<AudioDeviceAttributes> devices);
- }
-
- private int addDevicesRole(
- ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap,
- AudioSystemInterface asi,
- int useCase, int role, @NonNull List<AudioDeviceAttributes> devices) {
- synchronized (rolesMap) {
- Pair<Integer, Integer> key = new Pair<>(useCase, role);
- List<AudioDeviceAttributes> roleDevices = new ArrayList<>();
- List<AudioDeviceAttributes> appliedDevices = new ArrayList<>();
-
- if (rolesMap.containsKey(key)) {
- roleDevices = rolesMap.get(key);
- for (AudioDeviceAttributes device : devices) {
- if (!roleDevices.contains(device)) {
- appliedDevices.add(device);
- }
- }
- } else {
- appliedDevices.addAll(devices);
- }
- if (appliedDevices.isEmpty()) {
- return AudioSystem.SUCCESS;
- }
- final int status = asi.deviceRoleAction(useCase, role, appliedDevices);
- if (status == AudioSystem.SUCCESS) {
- roleDevices.addAll(appliedDevices);
- rolesMap.put(key, roleDevices);
- }
- return status;
- }
- }
-
- private int removeDevicesRole(
- ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap,
- AudioSystemInterface asi,
- int useCase, int role, @NonNull List<AudioDeviceAttributes> devices) {
- synchronized (rolesMap) {
- Pair<Integer, Integer> key = new Pair<>(useCase, role);
- if (!rolesMap.containsKey(key)) {
- return AudioSystem.SUCCESS;
- }
- List<AudioDeviceAttributes> roleDevices = rolesMap.get(key);
- List<AudioDeviceAttributes> appliedDevices = new ArrayList<>();
- for (AudioDeviceAttributes device : devices) {
- if (roleDevices.contains(device)) {
- appliedDevices.add(device);
- }
- }
- if (appliedDevices.isEmpty()) {
- return AudioSystem.SUCCESS;
- }
- final int status = asi.deviceRoleAction(useCase, role, appliedDevices);
- if (status == AudioSystem.SUCCESS) {
- roleDevices.removeAll(appliedDevices);
- if (roleDevices.isEmpty()) {
- rolesMap.remove(key);
- } else {
- rolesMap.put(key, roleDevices);
- }
- }
- return status;
- }
- }
-
- private int setDevicesRole(
- ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap,
- AudioSystemInterface addOp,
- AudioSystemInterface clearOp,
- int useCase, int role, @NonNull List<AudioDeviceAttributes> devices) {
- synchronized (rolesMap) {
- Pair<Integer, Integer> key = new Pair<>(useCase, role);
- List<AudioDeviceAttributes> roleDevices = new ArrayList<>();
- List<AudioDeviceAttributes> appliedDevices = new ArrayList<>();
-
- if (rolesMap.containsKey(key)) {
- roleDevices = rolesMap.get(key);
- boolean equal = false;
- if (roleDevices.size() == devices.size()) {
- roleDevices.retainAll(devices);
- equal = roleDevices.size() == devices.size();
- }
- if (!equal) {
- clearOp.deviceRoleAction(useCase, role, null);
- roleDevices.clear();
- appliedDevices.addAll(devices);
- }
- } else {
- appliedDevices.addAll(devices);
- }
- if (appliedDevices.isEmpty()) {
- return AudioSystem.SUCCESS;
- }
- final int status = addOp.deviceRoleAction(useCase, role, appliedDevices);
- if (status == AudioSystem.SUCCESS) {
- roleDevices.addAll(appliedDevices);
- rolesMap.put(key, roleDevices);
- }
- return status;
- }
- }
-
- private int clearDevicesRole(
- ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap,
- AudioSystemInterface asi, int useCase, int role) {
- synchronized (rolesMap) {
- Pair<Integer, Integer> key = new Pair<>(useCase, role);
- if (!rolesMap.containsKey(key)) {
- return AudioSystem.SUCCESS;
- }
- final int status = asi.deviceRoleAction(useCase, role, null);
- if (status == AudioSystem.SUCCESS) {
- rolesMap.remove(key);
- }
- return status;
- }
- }
-
- @GuardedBy("mDevicesLock")
- private void purgeDevicesRoles_l() {
- purgeRoles(mAppliedStrategyRoles, (s, r, d) -> {
- return mAudioSystem.removeDevicesRoleForStrategy(s, r, d); });
- purgeRoles(mAppliedPresetRoles, (p, r, d) -> {
- return mAudioSystem.removeDevicesRoleForCapturePreset(p, r, d); });
- }
-
- @GuardedBy("mDevicesLock")
- private void purgeRoles(
- ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap,
- AudioSystemInterface asi) {
- synchronized (rolesMap) {
- Iterator<Map.Entry<Pair<Integer, Integer>, List<AudioDeviceAttributes>>> itRole =
- rolesMap.entrySet().iterator();
- while (itRole.hasNext()) {
- Map.Entry<Pair<Integer, Integer>, List<AudioDeviceAttributes>> entry =
- itRole.next();
- Pair<Integer, Integer> keyRole = entry.getKey();
- Iterator<AudioDeviceAttributes> itDev = rolesMap.get(keyRole).iterator();
- while (itDev.hasNext()) {
- AudioDeviceAttributes ada = itDev.next();
- final String devKey = DeviceInfo.makeDeviceListKey(ada.getInternalType(),
- ada.getAddress());
- if (mConnectedDevices.get(devKey) == null) {
- asi.deviceRoleAction(keyRole.first, keyRole.second, Arrays.asList(ada));
- itDev.remove();
- }
- }
- if (rolesMap.get(keyRole).isEmpty()) {
- itRole.remove();
- }
- }
- }
- }
-
-//-----------------------------------------------------------------------
+ //-----------------------------------------------------------------------
/**
* Check if a device is in the list of connected devices
@@ -1168,11 +871,10 @@
* @param connect true if connection
* @param isForTesting if true, not calling AudioSystem for the connection as this is
* just for testing
- * @param btDevice the corresponding Bluetooth device when relevant.
* @return false if an error was reported by AudioSystem
*/
/*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect,
- boolean isForTesting, @Nullable BluetoothDevice btDevice) {
+ boolean isForTesting) {
int device = attributes.getInternalType();
String address = attributes.getAddress();
String deviceName = attributes.getName();
@@ -1187,7 +889,6 @@
.set(MediaMetrics.Property.MODE, connect
? MediaMetrics.Value.CONNECT : MediaMetrics.Value.DISCONNECT)
.set(MediaMetrics.Property.NAME, deviceName);
- boolean status = false;
synchronized (mDevicesLock) {
final String deviceKey = DeviceInfo.makeDeviceListKey(device, address);
if (AudioService.DEBUG_DEVICES) {
@@ -1215,33 +916,24 @@
.record();
return false;
}
- mConnectedDevices.put(deviceKey, new DeviceInfo(device, deviceName, address));
+ mConnectedDevices.put(deviceKey, new DeviceInfo(
+ device, deviceName, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
mDeviceBroker.postAccessoryPlugMediaUnmute(device);
- status = true;
+ mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
+ return true;
} else if (!connect && isConnected) {
mAudioSystem.setDeviceConnectionState(attributes,
AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
// always remove even if disconnection failed
mConnectedDevices.remove(deviceKey);
- status = true;
- }
- if (status) {
- if (AudioSystem.isBluetoothScoDevice(device)) {
- updateBluetoothPreferredModes_l();
- if (connect) {
- mDeviceBroker.postNotifyPreferredAudioProfileApplied(btDevice);
- } else {
- purgeDevicesRoles_l();
- }
- }
mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
- } else {
- Log.w(TAG, "handleDeviceConnection() failed, deviceKey=" + deviceKey
- + ", deviceSpec=" + di + ", connect=" + connect);
- mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.DISCONNECTED).record();
+ return true;
}
+ Log.w(TAG, "handleDeviceConnection() failed, deviceKey=" + deviceKey
+ + ", deviceSpec=" + di + ", connect=" + connect);
}
- return status;
+ mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.DISCONNECTED).record();
+ return false;
}
@@ -1450,20 +1142,15 @@
// Internal utilities
@GuardedBy("mDevicesLock")
- private void makeA2dpDeviceAvailable(AudioDeviceBroker.BtDeviceInfo btInfo,
- String eventSource) {
- final String address = btInfo.mDevice.getAddress();
- final String name = BtHelper.getName(btInfo.mDevice);
- final int a2dpCodec = btInfo.mCodec;
-
+ private void makeA2dpDeviceAvailable(String address, String name, String eventSource,
+ int a2dpCodec) {
// enable A2DP before notifying A2DP connection to avoid unnecessary processing in
// audio policy manager
mDeviceBroker.setBluetoothA2dpOnInt(true, true /*fromA2dp*/, eventSource);
// at this point there could be another A2DP device already connected in APM, but it
// doesn't matter as this new one will overwrite the previous one
- AudioDeviceAttributes ada = new AudioDeviceAttributes(
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name);
- final int res = mAudioSystem.setDeviceConnectionState(ada,
+ final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name),
AudioSystem.DEVICE_STATE_AVAILABLE, a2dpCodec);
// TODO: log in MediaMetrics once distinction between connection failure and
@@ -1485,7 +1172,8 @@
// The convention for head tracking sensors associated with A2DP devices is to
// use a UUID derived from the MAC address as follows:
// time_low = 0, time_mid = 0, time_hi = 0, clock_seq = 0, node = MAC Address
- UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada);
+ UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(
+ new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
final DeviceInfo di = new DeviceInfo(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
address, a2dpCodec, sensorUuid);
final String diKey = di.getKey();
@@ -1496,206 +1184,6 @@
mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
setCurrentAudioRouteNameIfPossible(name, true /*fromA2dp*/);
-
- updateBluetoothPreferredModes_l();
- mDeviceBroker.postNotifyPreferredAudioProfileApplied(btInfo.mDevice);
- }
-
- static final int[] CAPTURE_PRESETS = new int[] {AudioSource.MIC, AudioSource.CAMCORDER,
- AudioSource.VOICE_RECOGNITION, AudioSource.VOICE_COMMUNICATION,
- AudioSource.UNPROCESSED, AudioSource.VOICE_PERFORMANCE, AudioSource.HOTWORD};
-
- // reflects system property persist.bluetooth.enable_dual_mode_audio
- final boolean mBluetoothDualModeEnabled;
- /**
- * Goes over all connected Bluetooth devices and set the audio policy device role to DISABLED
- * or not according to their own and other devices modes.
- * The top priority is given to LE devices, then SCO ,then A2DP.
- */
- @GuardedBy("mDevicesLock")
- private void applyConnectedDevicesRoles_l() {
- if (!mBluetoothDualModeEnabled) {
- return;
- }
- DeviceInfo leOutDevice =
- getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_BLE_SET);
- DeviceInfo leInDevice =
- getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_IN_ALL_BLE_SET);
- DeviceInfo a2dpDevice =
- getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
- DeviceInfo scoOutDevice =
- getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_SCO_SET);
- DeviceInfo scoInDevice =
- getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_IN_ALL_SCO_SET);
- boolean disableA2dp = (leOutDevice != null && leOutDevice.isOutputOnlyModeEnabled());
- boolean disableSco = (leOutDevice != null && leOutDevice.isDuplexModeEnabled())
- || (leInDevice != null && leInDevice.isDuplexModeEnabled());
- AudioDeviceAttributes communicationDevice =
- mDeviceBroker.mActiveCommunicationDevice == null
- ? null : ((mDeviceBroker.isInCommunication()
- && mDeviceBroker.mActiveCommunicationDevice != null)
- ? new AudioDeviceAttributes(mDeviceBroker.mActiveCommunicationDevice)
- : null);
-
- if (AudioService.DEBUG_DEVICES) {
- Log.i(TAG, "applyConnectedDevicesRoles_l\n - leOutDevice: " + leOutDevice
- + "\n - leInDevice: " + leInDevice
- + "\n - a2dpDevice: " + a2dpDevice
- + "\n - scoOutDevice: " + scoOutDevice
- + "\n - scoInDevice: " + scoInDevice
- + "\n - disableA2dp: " + disableA2dp
- + ", disableSco: " + disableSco);
- }
-
- for (DeviceInfo di : mConnectedDevices.values()) {
- if (!AudioSystem.isBluetoothDevice(di.mDeviceType)) {
- continue;
- }
- AudioDeviceAttributes ada =
- new AudioDeviceAttributes(di.mDeviceType, di.mDeviceAddress, di.mDeviceName);
- if (AudioService.DEBUG_DEVICES) {
- Log.i(TAG, " + checking Device: " + ada);
- }
- if (ada.equalTypeAddress(communicationDevice)) {
- continue;
- }
-
- if (AudioSystem.isBluetoothOutDevice(di.mDeviceType)) {
- for (AudioProductStrategy strategy : mStrategies) {
- boolean disable = false;
- if (strategy.getId() == mDeviceBroker.mCommunicationStrategyId) {
- if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) {
- disable = disableSco || !di.isDuplexModeEnabled();
- } else if (AudioSystem.isBluetoothLeDevice(di.mDeviceType)) {
- disable = !di.isDuplexModeEnabled();
- }
- } else {
- if (AudioSystem.isBluetoothA2dpOutDevice(di.mDeviceType)) {
- disable = disableA2dp || !di.isOutputOnlyModeEnabled();
- } else if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) {
- disable = disableSco || !di.isOutputOnlyModeEnabled();
- } else if (AudioSystem.isBluetoothLeDevice(di.mDeviceType)) {
- disable = !di.isOutputOnlyModeEnabled();
- }
- }
- if (AudioService.DEBUG_DEVICES) {
- Log.i(TAG, " - strategy: " + strategy.getId()
- + ", disable: " + disable);
- }
- if (disable) {
- addDevicesRoleForStrategy(strategy.getId(),
- AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada));
- } else {
- removeDevicesRoleForStrategy(strategy.getId(),
- AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada));
- }
- }
- }
- if (AudioSystem.isBluetoothInDevice(di.mDeviceType)) {
- for (int capturePreset : CAPTURE_PRESETS) {
- boolean disable = false;
- if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) {
- disable = disableSco || !di.isDuplexModeEnabled();
- } else if (AudioSystem.isBluetoothLeDevice(di.mDeviceType)) {
- disable = !di.isDuplexModeEnabled();
- }
- if (AudioService.DEBUG_DEVICES) {
- Log.i(TAG, " - capturePreset: " + capturePreset
- + ", disable: " + disable);
- }
- if (disable) {
- addDevicesRoleForCapturePreset(capturePreset,
- AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada));
- } else {
- removeDevicesRoleForCapturePreset(capturePreset,
- AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada));
- }
- }
- }
- }
- }
-
- /* package */ void applyConnectedDevicesRoles() {
- synchronized (mDevicesLock) {
- applyConnectedDevicesRoles_l();
- }
- }
-
- @GuardedBy("mDevicesLock")
- int checkProfileIsConnected(int profile) {
- switch (profile) {
- case BluetoothProfile.HEADSET:
- if (getFirstConnectedDeviceOfTypes(
- AudioSystem.DEVICE_OUT_ALL_SCO_SET) != null
- || getFirstConnectedDeviceOfTypes(
- AudioSystem.DEVICE_IN_ALL_SCO_SET) != null) {
- return profile;
- }
- break;
- case BluetoothProfile.A2DP:
- if (getFirstConnectedDeviceOfTypes(
- AudioSystem.DEVICE_OUT_ALL_A2DP_SET) != null) {
- return profile;
- }
- break;
- case BluetoothProfile.LE_AUDIO:
- case BluetoothProfile.LE_AUDIO_BROADCAST:
- if (getFirstConnectedDeviceOfTypes(
- AudioSystem.DEVICE_OUT_ALL_BLE_SET) != null
- || getFirstConnectedDeviceOfTypes(
- AudioSystem.DEVICE_IN_ALL_BLE_SET) != null) {
- return profile;
- }
- break;
- default:
- break;
- }
- return 0;
- }
-
- @GuardedBy("mDevicesLock")
- private void updateBluetoothPreferredModes_l() {
- if (!mBluetoothDualModeEnabled) {
- return;
- }
- HashSet<String> processedAddresses = new HashSet<>(0);
- for (DeviceInfo di : mConnectedDevices.values()) {
- if (!AudioSystem.isBluetoothDevice(di.mDeviceType)
- || processedAddresses.contains(di.mDeviceAddress)) {
- continue;
- }
- Bundle preferredProfiles = BtHelper.getPreferredAudioProfiles(di.mDeviceAddress);
- if (AudioService.DEBUG_DEVICES) {
- Log.i(TAG, "updateBluetoothPreferredModes_l processing device address: "
- + di.mDeviceAddress + ", preferredProfiles: " + preferredProfiles);
- }
- for (DeviceInfo di2 : mConnectedDevices.values()) {
- if (!AudioSystem.isBluetoothDevice(di2.mDeviceType)
- || !di.mDeviceAddress.equals(di2.mDeviceAddress)) {
- continue;
- }
- int profile = BtHelper.getProfileFromType(di2.mDeviceType);
- if (profile == 0) {
- continue;
- }
- int preferredProfile = checkProfileIsConnected(
- preferredProfiles.getInt(BluetoothAdapter.AUDIO_MODE_DUPLEX));
- if (preferredProfile == profile || preferredProfile == 0) {
- di2.setModeEnabled(BluetoothAdapter.AUDIO_MODE_DUPLEX);
- } else {
- di2.setModeDisabled(BluetoothAdapter.AUDIO_MODE_DUPLEX);
- }
- preferredProfile = checkProfileIsConnected(
- preferredProfiles.getInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY));
- if (preferredProfile == profile || preferredProfile == 0) {
- di2.setModeEnabled(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY);
- } else {
- di2.setModeDisabled(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY);
- }
- }
- processedAddresses.add(di.mDeviceAddress);
- }
- applyConnectedDevicesRoles_l();
}
@GuardedBy("mDevicesLock")
@@ -1743,9 +1231,6 @@
// Remove A2DP routes as well
setCurrentAudioRouteNameIfPossible(null, true /*fromA2dp*/);
mmi.record();
-
- updateBluetoothPreferredModes_l();
- purgeDevicesRoles_l();
}
@GuardedBy("mDevicesLock")
@@ -1775,7 +1260,8 @@
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
- new DeviceInfo(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "", address));
+ new DeviceInfo(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
+ address, AudioSystem.AUDIO_FORMAT_DEFAULT));
}
@GuardedBy("mDevicesLock")
@@ -1801,7 +1287,8 @@
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
- new DeviceInfo(AudioSystem.DEVICE_OUT_HEARING_AID, name, address));
+ new DeviceInfo(AudioSystem.DEVICE_OUT_HEARING_AID, name,
+ address, AudioSystem.AUDIO_FORMAT_DEFAULT));
mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_HEARING_AID);
mDeviceBroker.postApplyVolumeOnDevice(streamType,
AudioSystem.DEVICE_OUT_HEARING_AID, "makeHearingAidDeviceAvailable");
@@ -1839,56 +1326,29 @@
* @return true if a DEVICE_OUT_HEARING_AID is connected, false otherwise.
*/
boolean isHearingAidConnected() {
- return getFirstConnectedDeviceOfTypes(
- Sets.newHashSet(AudioSystem.DEVICE_OUT_HEARING_AID)) != null;
- }
-
- /**
- * Returns a DeviceInfo for the fist connected device matching one of the supplied types
- */
- private DeviceInfo getFirstConnectedDeviceOfTypes(Set<Integer> internalTypes) {
- List<DeviceInfo> devices = getConnectedDevicesOfTypes(internalTypes);
- return devices.isEmpty() ? null : devices.get(0);
- }
-
- /**
- * Returns a list of connected devices matching one one of the supplied types
- */
- private List<DeviceInfo> getConnectedDevicesOfTypes(Set<Integer> internalTypes) {
- ArrayList<DeviceInfo> devices = new ArrayList<>();
synchronized (mDevicesLock) {
for (DeviceInfo di : mConnectedDevices.values()) {
- if (internalTypes.contains(di.mDeviceType)) {
- devices.add(di);
+ if (di.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) {
+ return true;
}
}
+ return false;
}
- return devices;
- }
-
- /* package */ AudioDeviceAttributes getDeviceOfType(int type) {
- DeviceInfo di = getFirstConnectedDeviceOfTypes(Sets.newHashSet(type));
- return di == null ? null : new AudioDeviceAttributes(
- di.mDeviceType, di.mDeviceAddress, di.mDeviceName);
}
@GuardedBy("mDevicesLock")
- private void makeLeAudioDeviceAvailable(
- AudioDeviceBroker.BtDeviceInfo btInfo, int streamType, String eventSource) {
- final String address = btInfo.mDevice.getAddress();
- final String name = BtHelper.getName(btInfo.mDevice);
- final int volumeIndex = btInfo.mVolume == -1 ? -1 : btInfo.mVolume * 10;
- final int device = btInfo.mAudioSystemDevice;
-
+ private void makeLeAudioDeviceAvailable(String address, String name, int streamType,
+ int volumeIndex, int device, String eventSource) {
if (device != AudioSystem.DEVICE_NONE) {
/* Audio Policy sees Le Audio similar to A2DP. Let's make sure
* AUDIO_POLICY_FORCE_NO_BT_A2DP is not set
*/
mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource);
- AudioDeviceAttributes ada = new AudioDeviceAttributes(device, address, name);
- final int res = AudioSystem.setDeviceConnectionState(ada,
- AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
+ final int res = AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+ device, address, name),
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ AudioSystem.AUDIO_FORMAT_DEFAULT);
if (res != AudioSystem.AUDIO_STATUS_OK) {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
"APM failed to make available LE Audio device addr=" + address
@@ -1899,13 +1359,12 @@
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
"LE Audio device addr=" + address + " now available").printLog(TAG));
}
+
// Reset LEA suspend state each time a new sink is connected
mDeviceBroker.clearLeAudioSuspended();
- UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada);
mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
- new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT,
- sensorUuid));
+ new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
mDeviceBroker.postAccessoryPlugMediaUnmute(device);
setCurrentAudioRouteNameIfPossible(name, /*fromA2dp=*/false);
}
@@ -1921,9 +1380,6 @@
final int maxIndex = mDeviceBroker.getMaxVssVolumeForStream(streamType);
mDeviceBroker.postSetLeAudioVolumeIndex(leAudioVolIndex, maxIndex, streamType);
mDeviceBroker.postApplyVolumeOnDevice(streamType, device, "makeLeAudioDeviceAvailable");
-
- updateBluetoothPreferredModes_l();
- mDeviceBroker.postNotifyPreferredAudioProfileApplied(btInfo.mDevice);
}
@GuardedBy("mDevicesLock")
@@ -1948,9 +1404,6 @@
}
setCurrentAudioRouteNameIfPossible(null, false /*fromA2dp*/);
-
- updateBluetoothPreferredModes_l();
- purgeDevicesRoles_l();
}
@GuardedBy("mDevicesLock")
@@ -2286,6 +1739,18 @@
}
}
+ /* package */ AudioDeviceAttributes getDeviceOfType(int type) {
+ synchronized (mDevicesLock) {
+ for (DeviceInfo di : mConnectedDevices.values()) {
+ if (di.mDeviceType == type) {
+ return new AudioDeviceAttributes(
+ di.mDeviceType, di.mDeviceAddress, di.mDeviceName);
+ }
+ }
+ }
+ return null;
+ }
+
//----------------------------------------------------------
// For tests only
@@ -2296,12 +1761,10 @@
*/
@VisibleForTesting
public boolean isA2dpDeviceConnected(@NonNull BluetoothDevice device) {
- for (DeviceInfo di : getConnectedDevicesOfTypes(
- Sets.newHashSet(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP))) {
- if (di.mDeviceAddress.equals(device.getAddress())) {
- return true;
- }
+ final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+ device.getAddress());
+ synchronized (mDevicesLock) {
+ return (mConnectedDevices.get(key) != null);
}
- return false;
}
}
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index 1142a8d..7af7ed5 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -435,7 +435,7 @@
}
/**
- * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int, List)}
+ * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int, int[], String[])}
* @param capturePreset
* @param role
* @param devicesToRemove
@@ -448,19 +448,6 @@
}
/**
- * Same as {@link AudioSystem#addDevicesRoleForCapturePreset(int, int, List)}
- * @param capturePreset the capture preset to configure
- * @param role the role of the devices
- * @param devices the list of devices to be added as role for the given capture preset
- * @return {@link #SUCCESS} if successfully add
- */
- public int addDevicesRoleForCapturePreset(
- int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) {
- invalidateRoutingCache();
- return AudioSystem.addDevicesRoleForCapturePreset(capturePreset, role, devices);
- }
-
- /**
* Same as {@link AudioSystem#}
* @param capturePreset
* @param role
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index e46c3cc..8c27c3e 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -33,7 +33,6 @@
import android.media.AudioSystem;
import android.media.BluetoothProfileConnectionInfo;
import android.os.Binder;
-import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -151,12 +150,60 @@
}
}
+ //----------------------------------------------------------------------
+ /*package*/ static class BluetoothA2dpDeviceInfo {
+ private final @NonNull BluetoothDevice mBtDevice;
+ private final int mVolume;
+ private final @AudioSystem.AudioFormatNativeEnumForBtCodec int mCodec;
+
+ BluetoothA2dpDeviceInfo(@NonNull BluetoothDevice btDevice) {
+ this(btDevice, -1, AudioSystem.AUDIO_FORMAT_DEFAULT);
+ }
+
+ BluetoothA2dpDeviceInfo(@NonNull BluetoothDevice btDevice, int volume, int codec) {
+ mBtDevice = btDevice;
+ mVolume = volume;
+ mCodec = codec;
+ }
+
+ public @NonNull BluetoothDevice getBtDevice() {
+ return mBtDevice;
+ }
+
+ public int getVolume() {
+ return mVolume;
+ }
+
+ public @AudioSystem.AudioFormatNativeEnumForBtCodec int getCodec() {
+ return mCodec;
+ }
+
+ // redefine equality op so we can match messages intended for this device
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) {
+ return false;
+ }
+ if (this == o) {
+ return true;
+ }
+ if (o instanceof BluetoothA2dpDeviceInfo) {
+ return mBtDevice.equals(((BluetoothA2dpDeviceInfo) o).getBtDevice());
+ }
+ return false;
+ }
+
+
+ }
+
// A2DP device events
/*package*/ static final int EVENT_DEVICE_CONFIG_CHANGE = 0;
+ /*package*/ static final int EVENT_ACTIVE_DEVICE_CHANGE = 1;
- /*package*/ static String deviceEventToString(int event) {
+ /*package*/ static String a2dpDeviceEventToString(int event) {
switch (event) {
case EVENT_DEVICE_CONFIG_CHANGE: return "DEVICE_CONFIG_CHANGE";
+ case EVENT_ACTIVE_DEVICE_CHANGE: return "ACTIVE_DEVICE_CHANGE";
default:
return new String("invalid event:" + event);
}
@@ -573,12 +620,11 @@
return btHeadsetDeviceToAudioDevice(mBluetoothHeadsetDevice);
}
- private static AudioDeviceAttributes btHeadsetDeviceToAudioDevice(BluetoothDevice btDevice) {
+ private AudioDeviceAttributes btHeadsetDeviceToAudioDevice(BluetoothDevice btDevice) {
if (btDevice == null) {
return new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
}
String address = btDevice.getAddress();
- String name = getName(btDevice);
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
address = "";
}
@@ -600,7 +646,7 @@
+ " btClass: " + (btClass == null ? "Unknown" : btClass)
+ " nativeType: " + nativeType + " address: " + address);
}
- return new AudioDeviceAttributes(nativeType, address, name);
+ return new AudioDeviceAttributes(nativeType, address);
}
private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
@@ -609,9 +655,12 @@
}
int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
AudioDeviceAttributes audioDevice = btHeadsetDeviceToAudioDevice(btDevice);
+ String btDeviceName = getName(btDevice);
boolean result = false;
if (isActive) {
- result |= mDeviceBroker.handleDeviceConnection(audioDevice, isActive, btDevice);
+ result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
+ audioDevice.getInternalType(), audioDevice.getAddress(), btDeviceName),
+ isActive);
} else {
int[] outDeviceTypes = {
AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
@@ -620,14 +669,14 @@
};
for (int outDeviceType : outDeviceTypes) {
result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
- outDeviceType, audioDevice.getAddress(), audioDevice.getName()),
- isActive, btDevice);
+ outDeviceType, audioDevice.getAddress(), btDeviceName),
+ isActive);
}
}
// handleDeviceConnection() && result to make sure the method get executed
result = mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
- inDevice, audioDevice.getAddress(), audioDevice.getName()),
- isActive, btDevice) && result;
+ inDevice, audioDevice.getAddress(), btDeviceName),
+ isActive) && result;
return result;
}
@@ -924,30 +973,6 @@
}
}
- /*package */ static int getProfileFromType(int deviceType) {
- if (AudioSystem.isBluetoothA2dpOutDevice(deviceType)) {
- return BluetoothProfile.A2DP;
- } else if (AudioSystem.isBluetoothScoDevice(deviceType)) {
- return BluetoothProfile.HEADSET;
- } else if (AudioSystem.isBluetoothLeDevice(deviceType)) {
- return BluetoothProfile.LE_AUDIO;
- }
- return 0; // 0 is not a valid profile
- }
-
- /*package */ static Bundle getPreferredAudioProfiles(String address) {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- return adapter.getPreferredAudioProfiles(adapter.getRemoteDevice(address));
- }
-
- /**
- * Notifies Bluetooth framework that new preferred audio profiles for Bluetooth devices
- * have been applied.
- */
- public static void onNotifyPreferredAudioProfileApplied(BluetoothDevice btDevice) {
- BluetoothAdapter.getDefaultAdapter().notifyActiveDeviceChangeApplied(btDevice);
- }
-
/**
* Returns the string equivalent for the btDeviceClass class.
*/
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index 31f0c05..a57dd40 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -303,8 +303,9 @@
SAFE_MEDIA_VOLUME_UNINITIALIZED);
mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
SAFE_MEDIA_VOLUME_UNINITIALIZED);
- mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- SAFE_MEDIA_VOLUME_UNINITIALIZED);
+ // TODO(b/278265907): enable A2DP when we can distinguish A2DP headsets
+ // mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+ // SAFE_MEDIA_VOLUME_UNINITIALIZED);
}
float getOutputRs2UpperBound() {
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthResultCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/AuthResultCoordinator.java
index a48a9d1..cd2a26f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthResultCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthResultCoordinator.java
@@ -37,13 +37,17 @@
*/
static final int AUTHENTICATOR_DEFAULT = 0;
/**
- * Indicated this authenticator has received a lockout.
+ * Indicated this authenticator has received a permanent lockout.
*/
- static final int AUTHENTICATOR_LOCKED = 1 << 0;
+ static final int AUTHENTICATOR_PERMANENT_LOCKED = 1 << 0;
+ /**
+ * Indicates this authenticator has received a timed unlock.
+ */
+ static final int AUTHENTICATOR_TIMED_LOCKED = 1 << 1;
/**
* Indicates this authenticator has received a successful unlock.
*/
- static final int AUTHENTICATOR_UNLOCKED = 1 << 1;
+ static final int AUTHENTICATOR_UNLOCKED = 1 << 2;
private static final String TAG = "AuthResultCoordinator";
private final Map<Integer, Integer> mAuthenticatorState;
@@ -85,7 +89,14 @@
* Adds a lock out of a given strength to the current operation list.
*/
void lockedOutFor(@Authenticators.Types int strength) {
- updateState(strength, (old) -> AUTHENTICATOR_LOCKED | old);
+ updateState(strength, (old) -> AUTHENTICATOR_PERMANENT_LOCKED | old);
+ }
+
+ /**
+ * Adds a timed lock out of a given strength to the current operation list.
+ */
+ void lockOutTimed(@Authenticators.Types int strength) {
+ updateState(strength, (old) -> AUTHENTICATOR_TIMED_LOCKED | old);
}
/**
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java
index 1aee5d4..2653ce7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthSessionCoordinator.java
@@ -16,21 +16,19 @@
package com.android.server.biometrics.sensors;
-import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_LOCKED;
+import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_PERMANENT_LOCKED;
+import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_TIMED_LOCKED;
import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_UNLOCKED;
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.os.SystemClock;
-import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import java.time.Clock;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
-import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -45,9 +43,7 @@
private final Set<Integer> mAuthOperations;
private final MultiBiometricLockoutState mMultiBiometricLockoutState;
- private final List<Pair<Integer, Long>> mTimedLockouts;
private final RingBuffer mRingBuffer;
- private final Clock mClock;
private int mUserId;
private boolean mIsAuthenticating;
@@ -63,8 +59,6 @@
mAuthResultCoordinator = new AuthResultCoordinator();
mMultiBiometricLockoutState = new MultiBiometricLockoutState(clock);
mRingBuffer = new RingBuffer(100);
- mTimedLockouts = new ArrayList<>();
- mClock = clock;
}
/**
@@ -74,8 +68,6 @@
mAuthOperations.clear();
mUserId = userId;
mIsAuthenticating = true;
- mAuthOperations.clear();
- mTimedLockouts.clear();
mAuthResultCoordinator = new AuthResultCoordinator();
mRingBuffer.addApiCall("internal : onAuthSessionStarted(" + userId + ")");
}
@@ -85,39 +77,30 @@
*
* This can happen two ways.
* 1. Manually calling this API
- * 2. If authStartedFor() was called, and all authentication attempts finish.
+ * 2. If authStartedFor() was called, and any authentication attempts finish.
*/
void endAuthSession() {
- if (mIsAuthenticating) {
- final long currentTime = mClock.millis();
- for (Pair<Integer, Long> timedLockouts : mTimedLockouts) {
- mMultiBiometricLockoutState.increaseLockoutTime(mUserId, timedLockouts.first,
- timedLockouts.second + currentTime);
+ // User unlocks can also unlock timed lockout Authenticator.Types
+ final Map<Integer, Integer> result = mAuthResultCoordinator.getResult();
+ for (int authenticator : Arrays.asList(Authenticators.BIOMETRIC_CONVENIENCE,
+ Authenticators.BIOMETRIC_WEAK, Authenticators.BIOMETRIC_STRONG)) {
+ final Integer value = result.get(authenticator);
+ if ((value & AUTHENTICATOR_UNLOCKED) == AUTHENTICATOR_UNLOCKED) {
+ mMultiBiometricLockoutState.clearPermanentLockOut(mUserId, authenticator);
+ mMultiBiometricLockoutState.clearTimedLockout(mUserId, authenticator);
+ } else if ((value & AUTHENTICATOR_PERMANENT_LOCKED) == AUTHENTICATOR_PERMANENT_LOCKED) {
+ mMultiBiometricLockoutState.setPermanentLockOut(mUserId, authenticator);
+ } else if ((value & AUTHENTICATOR_TIMED_LOCKED) == AUTHENTICATOR_TIMED_LOCKED) {
+ mMultiBiometricLockoutState.setTimedLockout(mUserId, authenticator);
}
- // User unlocks can also unlock timed lockout Authenticator.Types
- final Map<Integer, Integer> result = mAuthResultCoordinator.getResult();
- for (int authenticator : Arrays.asList(Authenticators.BIOMETRIC_CONVENIENCE,
- Authenticators.BIOMETRIC_WEAK, Authenticators.BIOMETRIC_STRONG)) {
- final Integer value = result.get(authenticator);
- if ((value & AUTHENTICATOR_UNLOCKED) == AUTHENTICATOR_UNLOCKED) {
- mMultiBiometricLockoutState.setAuthenticatorTo(mUserId, authenticator,
- true /* canAuthenticate */);
- mMultiBiometricLockoutState.clearLockoutTime(mUserId, authenticator);
- } else if ((value & AUTHENTICATOR_LOCKED) == AUTHENTICATOR_LOCKED) {
- mMultiBiometricLockoutState.setAuthenticatorTo(mUserId, authenticator,
- false /* canAuthenticate */);
- }
-
- }
-
- mRingBuffer.addApiCall("internal : onAuthSessionEnded(" + mUserId + ")");
- clearSession();
}
+
+ mRingBuffer.addApiCall("internal : onAuthSessionEnded(" + mUserId + ")");
+ clearSession();
}
private void clearSession() {
mIsAuthenticating = false;
- mTimedLockouts.clear();
mAuthOperations.clear();
}
@@ -171,7 +154,7 @@
+ ", sensorId=" + sensorId + "time=" + time + ", requestId=" + requestId
+ ")";
mRingBuffer.addApiCall(lockedOutStr);
- mTimedLockouts.add(new Pair<>(biometricStrength, time));
+ mAuthResultCoordinator.lockOutTimed(biometricStrength);
attemptToFinish(userId, sensorId, lockedOutStr);
}
@@ -202,9 +185,8 @@
// Lockouts cannot be reset by non-strong biometrics
return;
}
- mMultiBiometricLockoutState.setAuthenticatorTo(userId, biometricStrength,
- true /*canAuthenticate */);
- mMultiBiometricLockoutState.clearLockoutTime(userId, biometricStrength);
+ mMultiBiometricLockoutState.clearPermanentLockOut(userId, biometricStrength);
+ mMultiBiometricLockoutState.clearTimedLockout(userId, biometricStrength);
}
private void attemptToFinish(int userId, int sensorId, String description) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java b/services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java
index c24a989..45933fe 100644
--- a/services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/MultiBiometricLockoutState.java
@@ -50,10 +50,11 @@
private Map<Integer, AuthenticatorState> createUnlockedMap() {
Map<Integer, AuthenticatorState> lockOutMap = new HashMap<>();
lockOutMap.put(BIOMETRIC_STRONG,
- new AuthenticatorState(BIOMETRIC_STRONG, false, 0, mClock));
- lockOutMap.put(BIOMETRIC_WEAK, new AuthenticatorState(BIOMETRIC_WEAK, false, 0, mClock));
+ new AuthenticatorState(BIOMETRIC_STRONG, false, false));
+ lockOutMap.put(BIOMETRIC_WEAK,
+ new AuthenticatorState(BIOMETRIC_WEAK, false, false));
lockOutMap.put(BIOMETRIC_CONVENIENCE,
- new AuthenticatorState(BIOMETRIC_CONVENIENCE, false, 0, mClock));
+ new AuthenticatorState(BIOMETRIC_CONVENIENCE, false, false));
return lockOutMap;
}
@@ -64,54 +65,71 @@
return mCanUserAuthenticate.get(userId);
}
- void setAuthenticatorTo(int userId, @Authenticators.Types int strength, boolean canAuth) {
+ void setPermanentLockOut(int userId, @Authenticators.Types int strength) {
final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId);
switch (strength) {
case Authenticators.BIOMETRIC_STRONG:
- authMap.get(BIOMETRIC_STRONG).mPermanentlyLockedOut = !canAuth;
+ authMap.get(BIOMETRIC_STRONG).mPermanentlyLockedOut = true;
// fall through
case Authenticators.BIOMETRIC_WEAK:
- authMap.get(BIOMETRIC_WEAK).mPermanentlyLockedOut = !canAuth;
+ authMap.get(BIOMETRIC_WEAK).mPermanentlyLockedOut = true;
// fall through
case Authenticators.BIOMETRIC_CONVENIENCE:
- authMap.get(BIOMETRIC_CONVENIENCE).mPermanentlyLockedOut = !canAuth;
+ authMap.get(BIOMETRIC_CONVENIENCE).mPermanentlyLockedOut = true;
return;
default:
Slog.e(TAG, "increaseLockoutTime called for invalid strength : " + strength);
}
}
- void increaseLockoutTime(int userId, @Authenticators.Types int strength, long duration) {
+ void clearPermanentLockOut(int userId, @Authenticators.Types int strength) {
final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId);
switch (strength) {
case Authenticators.BIOMETRIC_STRONG:
- authMap.get(BIOMETRIC_STRONG).increaseLockoutTo(duration);
+ authMap.get(BIOMETRIC_STRONG).mPermanentlyLockedOut = false;
// fall through
case Authenticators.BIOMETRIC_WEAK:
- authMap.get(BIOMETRIC_WEAK).increaseLockoutTo(duration);
+ authMap.get(BIOMETRIC_WEAK).mPermanentlyLockedOut = false;
// fall through
case Authenticators.BIOMETRIC_CONVENIENCE:
- authMap.get(BIOMETRIC_CONVENIENCE).increaseLockoutTo(duration);
+ authMap.get(BIOMETRIC_CONVENIENCE).mPermanentlyLockedOut = false;
return;
default:
Slog.e(TAG, "increaseLockoutTime called for invalid strength : " + strength);
}
}
- void clearLockoutTime(int userId, @Authenticators.Types int strength) {
+ void setTimedLockout(int userId, @Authenticators.Types int strength) {
final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId);
switch (strength) {
case Authenticators.BIOMETRIC_STRONG:
- authMap.get(BIOMETRIC_STRONG).setTimedLockout(0);
+ authMap.get(BIOMETRIC_STRONG).mTimedLockout = true;
// fall through
case Authenticators.BIOMETRIC_WEAK:
- authMap.get(BIOMETRIC_WEAK).setTimedLockout(0);
+ authMap.get(BIOMETRIC_WEAK).mTimedLockout = true;
// fall through
case Authenticators.BIOMETRIC_CONVENIENCE:
- authMap.get(BIOMETRIC_CONVENIENCE).setTimedLockout(0);
+ authMap.get(BIOMETRIC_CONVENIENCE).mTimedLockout = true;
return;
default:
- Slog.e(TAG, "clearLockoutTime called for invalid strength : " + strength);
+ Slog.e(TAG, "increaseLockoutTime called for invalid strength : " + strength);
+ }
+ }
+
+ void clearTimedLockout(int userId, @Authenticators.Types int strength) {
+ final Map<Integer, AuthenticatorState> authMap = getAuthMapForUser(userId);
+ switch (strength) {
+ case Authenticators.BIOMETRIC_STRONG:
+ authMap.get(BIOMETRIC_STRONG).mTimedLockout = false;
+ // fall through
+ case Authenticators.BIOMETRIC_WEAK:
+ authMap.get(BIOMETRIC_WEAK).mTimedLockout = false;
+ // fall through
+ case Authenticators.BIOMETRIC_CONVENIENCE:
+ authMap.get(BIOMETRIC_CONVENIENCE).mTimedLockout = false;
+ return;
+ default:
+ Slog.e(TAG, "increaseLockoutTime called for invalid strength : " + strength);
}
}
@@ -132,7 +150,7 @@
final AuthenticatorState state = authMap.get(strength);
if (state.mPermanentlyLockedOut) {
return LockoutTracker.LOCKOUT_PERMANENT;
- } else if (state.isTimedLockout()) {
+ } else if (state.mTimedLockout) {
return LockoutTracker.LOCKOUT_TIMED;
} else {
return LockoutTracker.LOCKOUT_NONE;
@@ -158,43 +176,21 @@
private static class AuthenticatorState {
private Integer mAuthenticatorType;
private boolean mPermanentlyLockedOut;
- private long mTimedLockout;
- private Clock mClock;
+ private boolean mTimedLockout;
AuthenticatorState(Integer authenticatorId, boolean permanentlyLockedOut,
- long timedLockout, Clock clock) {
+ boolean timedLockout) {
mAuthenticatorType = authenticatorId;
mPermanentlyLockedOut = permanentlyLockedOut;
mTimedLockout = timedLockout;
- mClock = clock;
- }
-
- boolean canAuthenticate() {
- return !mPermanentlyLockedOut && !isTimedLockout();
- }
-
- boolean isTimedLockout() {
- return mClock.millis() - mTimedLockout < 0;
- }
-
- void setTimedLockout(long duration) {
- mTimedLockout = duration;
- }
-
- /**
- * Either increases the lockout to duration, or leaves it as it, whichever is longer.
- */
- void increaseLockoutTo(long duration) {
- mTimedLockout = Math.max(mTimedLockout, duration);
}
String toString(long currentTime) {
- final String duration =
- mTimedLockout - currentTime > 0 ? (mTimedLockout - currentTime) + "ms" : "none";
+ final String timedLockout = mTimedLockout ? "true" : "false";
final String permanentLockout = mPermanentlyLockedOut ? "true" : "false";
- return String.format("(%s, permanentLockout=%s, timedLockoutRemaining=%s)",
+ return String.format("(%s, permanentLockout=%s, timedLockout=%s)",
BiometricManager.authenticatorToStr(mAuthenticatorType), permanentLockout,
- duration);
+ timedLockout);
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
index 759c52a..1a12fcd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
@@ -28,6 +28,7 @@
import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ErrorConsumer;
import com.android.server.biometrics.sensors.HalClientMonitor;
@@ -88,10 +89,9 @@
void onLockoutCleared() {
resetLocalLockoutStateToNone(getSensorId(), getTargetUserId(), mLockoutCache,
- mLockoutResetDispatcher);
+ mLockoutResetDispatcher, getBiometricContext().getAuthSessionCoordinator(),
+ mBiometricStrength, getRequestId());
mCallback.onClientFinished(this, true /* success */);
- getBiometricContext().getAuthSessionCoordinator()
- .resetLockoutFor(getTargetUserId(), mBiometricStrength, getRequestId());
}
public boolean interruptsPrecedingClients() {
@@ -108,7 +108,10 @@
*/
static void resetLocalLockoutStateToNone(int sensorId, int userId,
@NonNull LockoutCache lockoutTracker,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull AuthSessionCoordinator authSessionCoordinator,
+ @Authenticators.Types int biometricStrength, long requestId) {
+ authSessionCoordinator.resetLockoutFor(userId, biometricStrength, requestId);
lockoutTracker.setLockoutModeForUser(userId, LockoutTracker.LOCKOUT_NONE);
lockoutResetDispatcher.notifyLockoutResetCallbacks(sensorId);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index 0d30ddd..468bf55 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -54,6 +54,7 @@
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
@@ -127,6 +128,9 @@
private final LockoutCache mLockoutCache;
@NonNull
private final LockoutResetDispatcher mLockoutResetDispatcher;
+
+ @NonNull
+ private AuthSessionCoordinator mAuthSessionCoordinator;
@NonNull
private final Callback mCallback;
@@ -134,6 +138,7 @@
@NonNull UserAwareBiometricScheduler scheduler, int sensorId, int userId,
@NonNull LockoutCache lockoutTracker,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull AuthSessionCoordinator authSessionCoordinator,
@NonNull Callback callback) {
mContext = context;
mHandler = handler;
@@ -143,6 +148,7 @@
mUserId = userId;
mLockoutCache = lockoutTracker;
mLockoutResetDispatcher = lockoutResetDispatcher;
+ mAuthSessionCoordinator = authSessionCoordinator;
mCallback = callback;
}
@@ -346,8 +352,12 @@
final BaseClientMonitor client = mScheduler.getCurrentClient();
if (!(client instanceof FaceResetLockoutClient)) {
Slog.d(mTag, "onLockoutCleared outside of resetLockout by HAL");
+ // Given that onLockoutCleared() can happen at any time, and is not necessarily
+ // coming from a specific client, set this to -1 to indicate it wasn't for a
+ // specific request.
FaceResetLockoutClient.resetLocalLockoutStateToNone(mSensorId, mUserId,
- mLockoutCache, mLockoutResetDispatcher);
+ mLockoutCache, mLockoutResetDispatcher, mAuthSessionCoordinator,
+ Utils.getCurrentStrength(mSensorId), -1 /* requestId */);
} else {
Slog.d(mTag, "onLockoutCleared after resetLockout");
final FaceResetLockoutClient resetLockoutClient =
@@ -514,7 +524,8 @@
final HalSessionCallback resultController = new HalSessionCallback(mContext,
mHandler, mTag, mScheduler, sensorId, newUserId, mLockoutCache,
- lockoutResetDispatcher, () -> {
+ lockoutResetDispatcher,
+ biometricContext.getAuthSessionCoordinator(), () -> {
Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE");
mCurrentSession = null;
});
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
index 0b2421b..7a62034 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
@@ -28,6 +28,7 @@
import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ErrorConsumer;
import com.android.server.biometrics.sensors.HalClientMonitor;
@@ -92,10 +93,9 @@
void onLockoutCleared() {
resetLocalLockoutStateToNone(getSensorId(), getTargetUserId(), mLockoutCache,
- mLockoutResetDispatcher);
+ mLockoutResetDispatcher, getBiometricContext().getAuthSessionCoordinator(),
+ mBiometricStrength, getRequestId());
mCallback.onClientFinished(this, true /* success */);
- getBiometricContext().getAuthSessionCoordinator()
- .resetLockoutFor(getTargetUserId(), mBiometricStrength, getRequestId());
}
/**
@@ -108,9 +108,12 @@
*/
static void resetLocalLockoutStateToNone(int sensorId, int userId,
@NonNull LockoutCache lockoutTracker,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull AuthSessionCoordinator authSessionCoordinator,
+ @Authenticators.Types int biometricStrength, long requestId) {
lockoutTracker.setLockoutModeForUser(userId, LockoutTracker.LOCKOUT_NONE);
lockoutResetDispatcher.notifyLockoutResetCallbacks(sensorId);
+ authSessionCoordinator.resetLockoutFor(userId, biometricStrength, requestId);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index 1dcf4e9..22ca816 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -52,6 +52,7 @@
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AcquisitionClient;
+import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
@@ -131,12 +132,15 @@
@NonNull
private final LockoutResetDispatcher mLockoutResetDispatcher;
@NonNull
+ private AuthSessionCoordinator mAuthSessionCoordinator;
+ @NonNull
private final Callback mCallback;
HalSessionCallback(@NonNull Context context, @NonNull Handler handler, @NonNull String tag,
@NonNull UserAwareBiometricScheduler scheduler, int sensorId, int userId,
@NonNull LockoutCache lockoutTracker,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull AuthSessionCoordinator authSessionCoordinator,
@NonNull Callback callback) {
mContext = context;
mHandler = handler;
@@ -146,6 +150,7 @@
mUserId = userId;
mLockoutCache = lockoutTracker;
mLockoutResetDispatcher = lockoutResetDispatcher;
+ mAuthSessionCoordinator = authSessionCoordinator;
mCallback = callback;
}
@@ -327,8 +332,12 @@
final BaseClientMonitor client = mScheduler.getCurrentClient();
if (!(client instanceof FingerprintResetLockoutClient)) {
Slog.d(mTag, "onLockoutCleared outside of resetLockout by HAL");
+ // Given that onLockoutCleared() can happen at any time, and is not necessarily
+ // coming from a specific client, set this to -1 to indicate it wasn't for a
+ // specific request.
FingerprintResetLockoutClient.resetLocalLockoutStateToNone(mSensorId, mUserId,
- mLockoutCache, mLockoutResetDispatcher);
+ mLockoutCache, mLockoutResetDispatcher, mAuthSessionCoordinator,
+ Utils.getCurrentStrength(mSensorId), -1 /* requestId */);
} else {
Slog.d(mTag, "onLockoutCleared after resetLockout");
final FingerprintResetLockoutClient resetLockoutClient =
@@ -470,7 +479,8 @@
final HalSessionCallback resultController = new HalSessionCallback(mContext,
mHandler, mTag, mScheduler, sensorId, newUserId, mLockoutCache,
- lockoutResetDispatcher, () -> {
+ lockoutResetDispatcher,
+ biometricContext.getAuthSessionCoordinator(), () -> {
Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE");
mCurrentSession = null;
});
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java
index a0befea..36d56c8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java
@@ -24,6 +24,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.Looper;
import android.os.SystemClock;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -69,6 +71,7 @@
private final SparseIntArray mFailedAttempts;
private final AlarmManager mAlarmManager;
private final LockoutReceiver mLockoutReceiver;
+ private final Handler mHandler;
public LockoutFrameworkImpl(Context context, LockoutResetCallback lockoutResetCallback) {
mContext = context;
@@ -77,6 +80,7 @@
mFailedAttempts = new SparseIntArray();
mAlarmManager = context.getSystemService(AlarmManager.class);
mLockoutReceiver = new LockoutReceiver();
+ mHandler = new Handler(Looper.getMainLooper());
context.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
RESET_FINGERPRINT_LOCKOUT, null /* handler */, Context.RECEIVER_EXPORTED);
@@ -127,9 +131,11 @@
}
private void scheduleLockoutResetForUser(int userId) {
- mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mHandler.post(() -> {
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
getLockoutResetIntentForUser(userId));
+ });
}
private PendingIntent getLockoutResetIntentForUser(int userId) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 0f17139..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 */
@@ -3744,20 +3804,26 @@
+ mUnderlyingNetworkCapabilities + " to " + nc);
final NetworkCapabilities oldNc = mUnderlyingNetworkCapabilities;
mUnderlyingNetworkCapabilities = nc;
- if (oldNc == null) {
- // A new default network is available.
- startOrMigrateIkeSession(mActiveNetwork);
- } else if (!nc.getSubscriptionIds().equals(oldNc.getSubscriptionIds())) {
- // Renew carrierConfig values.
- maybeMigrateIkeSessionAndUpdateVpnTransportInfo(mActiveNetwork);
+ 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.
+ 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
@@ -4035,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.
@@ -4472,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/devicestate/DeviceStateNotificationController.java b/services/core/java/com/android/server/devicestate/DeviceStateNotificationController.java
index ab261ac..f4c84e7 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateNotificationController.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateNotificationController.java
@@ -37,8 +37,11 @@
import android.util.SparseArray;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.Locale;
+
/**
* Manages the user-visible device state notifications.
*/
@@ -56,15 +59,14 @@
private final NotificationManager mNotificationManager;
private final PackageManager mPackageManager;
- // Stores the notification title and content indexed with the device state identifier.
- private final SparseArray<NotificationInfo> mNotificationInfos;
-
// The callback when a device state is requested to be canceled.
private final Runnable mCancelStateRunnable;
+ private final NotificationInfoProvider mNotificationInfoProvider;
+
DeviceStateNotificationController(@NonNull Context context, @NonNull Handler handler,
@NonNull Runnable cancelStateRunnable) {
- this(context, handler, cancelStateRunnable, getNotificationInfos(context),
+ this(context, handler, cancelStateRunnable, new NotificationInfoProvider(context),
context.getPackageManager(), context.getSystemService(NotificationManager.class));
}
@@ -72,13 +74,13 @@
DeviceStateNotificationController(
@NonNull Context context, @NonNull Handler handler,
@NonNull Runnable cancelStateRunnable,
- @NonNull SparseArray<NotificationInfo> notificationInfos,
+ @NonNull NotificationInfoProvider notificationInfoProvider,
@NonNull PackageManager packageManager,
@NonNull NotificationManager notificationManager) {
mContext = context;
mHandler = handler;
mCancelStateRunnable = cancelStateRunnable;
- mNotificationInfos = notificationInfos;
+ mNotificationInfoProvider = notificationInfoProvider;
mPackageManager = packageManager;
mNotificationManager = notificationManager;
mContext.registerReceiver(
@@ -97,7 +99,7 @@
* @param requestingAppUid the uid of the requesting app used to retrieve the app name.
*/
void showStateActiveNotificationIfNeeded(int state, int requestingAppUid) {
- NotificationInfo info = mNotificationInfos.get(state);
+ NotificationInfo info = getNotificationInfos().get(state);
if (info == null || !info.hasActiveNotification()) {
return;
}
@@ -127,7 +129,7 @@
* @param state the identifier of the device state being canceled.
*/
void showThermalCriticalNotificationIfNeeded(int state) {
- NotificationInfo info = mNotificationInfos.get(state);
+ NotificationInfo info = getNotificationInfos().get(state);
if (info == null || !info.hasThermalCriticalNotification()) {
return;
}
@@ -148,7 +150,7 @@
* @param state the identifier of the device state being canceled.
*/
void showPowerSaveNotificationIfNeeded(int state) {
- NotificationInfo info = mNotificationInfos.get(state);
+ NotificationInfo info = getNotificationInfos().get(state);
if (info == null || !info.hasPowerSaveModeNotification()) {
return;
}
@@ -170,7 +172,7 @@
* @param state the device state identifier.
*/
void cancelNotification(int state) {
- if (!mNotificationInfos.contains(state)) {
+ if (getNotificationInfos().get(state) == null) {
return;
}
mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
@@ -221,69 +223,121 @@
mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build());
}
- /**
- * Loads the resources for the notifications. The device state identifiers and strings are
- * stored in arrays. All the string arrays must have the same length and same order as the
- * identifier array.
- */
- private static SparseArray<NotificationInfo> getNotificationInfos(Context context) {
- final SparseArray<NotificationInfo> notificationInfos = new SparseArray<>();
+ private SparseArray<NotificationInfo> getNotificationInfos() {
+ Locale locale = mContext.getResources().getConfiguration().getLocales().get(0);
+ return mNotificationInfoProvider.getNotificationInfos(locale);
+ }
- final int[] stateIdentifiers =
- context.getResources().getIntArray(
- R.array.device_state_notification_state_identifiers);
- final String[] names =
- context.getResources().getStringArray(R.array.device_state_notification_names);
- final String[] activeNotificationTitles =
- context.getResources().getStringArray(
- R.array.device_state_notification_active_titles);
- final String[] activeNotificationContents =
- context.getResources().getStringArray(
- R.array.device_state_notification_active_contents);
- final String[] thermalCriticalNotificationTitles =
- context.getResources().getStringArray(
- R.array.device_state_notification_thermal_titles);
- final String[] thermalCriticalNotificationContents =
- context.getResources().getStringArray(
- R.array.device_state_notification_thermal_contents);
- final String[] powerSaveModeNotificationTitles =
- context.getResources().getStringArray(
- R.array.device_state_notification_power_save_titles);
- final String[] powerSaveModeNotificationContents =
- context.getResources().getStringArray(
- R.array.device_state_notification_power_save_contents);
+ @VisibleForTesting
+ public static class NotificationInfoProvider {
+ @NonNull
+ private final Context mContext;
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ @Nullable
+ private SparseArray<NotificationInfo> mCachedNotificationInfos;
- if (stateIdentifiers.length != names.length
- || stateIdentifiers.length != activeNotificationTitles.length
- || stateIdentifiers.length != activeNotificationContents.length
- || stateIdentifiers.length != thermalCriticalNotificationTitles.length
- || stateIdentifiers.length != thermalCriticalNotificationContents.length
- || stateIdentifiers.length != powerSaveModeNotificationTitles.length
- || stateIdentifiers.length != powerSaveModeNotificationContents.length
- ) {
- throw new IllegalStateException(
- "The length of state identifiers and notification texts must match!");
+ @GuardedBy("mLock")
+ @Nullable
+ @VisibleForTesting
+ Locale mCachedLocale;
+
+ NotificationInfoProvider(@NonNull Context context) {
+ mContext = context;
}
- for (int i = 0; i < stateIdentifiers.length; i++) {
- int identifier = stateIdentifiers[i];
- if (identifier == DeviceStateManager.INVALID_DEVICE_STATE) {
- continue;
+ /**
+ * Loads the resources for the notifications. The device state identifiers and strings are
+ * stored in arrays. All the string arrays must have the same length and same order as the
+ * identifier array.
+ */
+ @NonNull
+ public SparseArray<NotificationInfo> getNotificationInfos(@NonNull Locale locale) {
+ synchronized (mLock) {
+ if (!locale.equals(mCachedLocale)) {
+ refreshNotificationInfos(locale);
+ }
+ return mCachedNotificationInfos;
+ }
+ }
+
+
+ @VisibleForTesting
+ Locale getCachedLocale() {
+ synchronized (mLock) {
+ return mCachedLocale;
+ }
+ }
+
+ @VisibleForTesting
+ public void refreshNotificationInfos(Locale locale) {
+ synchronized (mLock) {
+ mCachedLocale = locale;
+ mCachedNotificationInfos = loadNotificationInfos();
+ }
+ }
+
+ @VisibleForTesting
+ public SparseArray<NotificationInfo> loadNotificationInfos() {
+ final SparseArray<NotificationInfo> notificationInfos = new SparseArray<>();
+
+ final int[] stateIdentifiers =
+ mContext.getResources().getIntArray(
+ R.array.device_state_notification_state_identifiers);
+ final String[] names =
+ mContext.getResources().getStringArray(R.array.device_state_notification_names);
+ final String[] activeNotificationTitles =
+ mContext.getResources().getStringArray(
+ R.array.device_state_notification_active_titles);
+ final String[] activeNotificationContents =
+ mContext.getResources().getStringArray(
+ R.array.device_state_notification_active_contents);
+ final String[] thermalCriticalNotificationTitles =
+ mContext.getResources().getStringArray(
+ R.array.device_state_notification_thermal_titles);
+ final String[] thermalCriticalNotificationContents =
+ mContext.getResources().getStringArray(
+ R.array.device_state_notification_thermal_contents);
+ final String[] powerSaveModeNotificationTitles =
+ mContext.getResources().getStringArray(
+ R.array.device_state_notification_power_save_titles);
+ final String[] powerSaveModeNotificationContents =
+ mContext.getResources().getStringArray(
+ R.array.device_state_notification_power_save_contents);
+
+ if (stateIdentifiers.length != names.length
+ || stateIdentifiers.length != activeNotificationTitles.length
+ || stateIdentifiers.length != activeNotificationContents.length
+ || stateIdentifiers.length != thermalCriticalNotificationTitles.length
+ || stateIdentifiers.length != thermalCriticalNotificationContents.length
+ || stateIdentifiers.length != powerSaveModeNotificationTitles.length
+ || stateIdentifiers.length != powerSaveModeNotificationContents.length
+ ) {
+ throw new IllegalStateException(
+ "The length of state identifiers and notification texts must match!");
}
- notificationInfos.put(
- identifier,
- new NotificationInfo(
- names[i], activeNotificationTitles[i], activeNotificationContents[i],
- thermalCriticalNotificationTitles[i],
- thermalCriticalNotificationContents[i],
- powerSaveModeNotificationTitles[i],
- powerSaveModeNotificationContents[i])
- );
- }
+ for (int i = 0; i < stateIdentifiers.length; i++) {
+ int identifier = stateIdentifiers[i];
+ if (identifier == DeviceStateManager.INVALID_DEVICE_STATE) {
+ continue;
+ }
- return notificationInfos;
+ notificationInfos.put(
+ identifier,
+ new NotificationInfo(
+ names[i],
+ activeNotificationTitles[i],
+ activeNotificationContents[i],
+ thermalCriticalNotificationTitles[i],
+ thermalCriticalNotificationContents[i],
+ powerSaveModeNotificationTitles[i],
+ powerSaveModeNotificationContents[i])
+ );
+ }
+ return notificationInfos;
+ }
}
/**
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/WakelockController.java b/services/core/java/com/android/server/display/WakelockController.java
index 6511f4f..1e13974 100644
--- a/services/core/java/com/android/server/display/WakelockController.java
+++ b/services/core/java/com/android/server/display/WakelockController.java
@@ -38,7 +38,9 @@
public static final int WAKE_LOCK_STATE_CHANGED = 4;
public static final int WAKE_LOCK_UNFINISHED_BUSINESS = 5;
- private static final int WAKE_LOCK_MAX = WAKE_LOCK_UNFINISHED_BUSINESS;
+ @VisibleForTesting
+ static final int WAKE_LOCK_MAX = WAKE_LOCK_UNFINISHED_BUSINESS;
+
private static final boolean DEBUG = false;
@IntDef(flag = true, prefix = "WAKE_LOCK_", value = {
@@ -132,7 +134,7 @@
* A utility to release all the wakelock acquired by the system
*/
public void releaseAll() {
- for (int i = WAKE_LOCK_PROXIMITY_POSITIVE; i < WAKE_LOCK_MAX; i++) {
+ for (int i = WAKE_LOCK_PROXIMITY_POSITIVE; i <= WAKE_LOCK_MAX; i++) {
releaseWakelockInternal(i);
}
}
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
index 01cae42..ad640b1 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -239,7 +239,7 @@
String[] certs = mContext.getResources().getStringArray(
R.array.config_fontManagerServiceCerts);
- if (mDebugCertFilePath != null && (Build.IS_USERDEBUG || Build.IS_ENG)) {
+ if (mDebugCertFilePath != null && Build.IS_DEBUGGABLE) {
String[] tmp = new String[certs.length + 1];
System.arraycopy(certs, 0, tmp, 0, certs.length);
tmp[certs.length] = mDebugCertFilePath;
@@ -251,8 +251,8 @@
}
/**
- * Add debug certificate to the cert list. This must be called only on userdebug/eng
- * build.
+ * Add debug certificate to the cert list. This must be called only on debuggable build.
+ *
* @param debugCertPath a debug certificate file path
*/
public void addDebugCertificate(@Nullable String debugCertPath) {
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java b/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
index c039a83..6d82841d 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
@@ -105,8 +105,8 @@
w.println(" Update font families with the new definitions.");
w.println();
w.println("install-debug-cert [cert file path]");
- w.println(" Install debug certificate file. This command can be used only on userdebug");
- w.println(" or eng device with root user.");
+ w.println(" Install debug certificate file. This command can be used only on");
+ w.println(" debuggable device with root user.");
w.println();
w.println("clear");
w.println(" Remove all installed font files and reset to the initial state.");
diff --git a/services/core/java/com/android/server/infra/OWNERS b/services/core/java/com/android/server/infra/OWNERS
index 0466d8a..4fea05d 100644
--- a/services/core/java/com/android/server/infra/OWNERS
+++ b/services/core/java/com/android/server/infra/OWNERS
@@ -1,3 +1,3 @@
# Bug component: 655446
-include /core/java/android/service/cloudsearch/OWNERS
+srazdan@google.com
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/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index ee4a6fe..a7e704e 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -116,6 +116,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
+import android.util.Log;
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -1229,6 +1230,26 @@
}
/**
+ * {@link LockPatternUtils#refreshStoredPinLength(int)}
+ * @param userId user id of the user whose pin length we want to save
+ * @return true/false depending on whether PIN length has been saved or not
+ */
+ @Override
+ public boolean refreshStoredPinLength(int userId) {
+ checkPasswordHavePermission();
+ synchronized (mSpManager) {
+ PasswordMetrics passwordMetrics = getUserPasswordMetrics(userId);
+ if (passwordMetrics != null) {
+ final long protectorId = getCurrentLskfBasedProtectorId(userId);
+ return mSpManager.refreshPinLengthOnDisk(passwordMetrics, protectorId, userId);
+ } else {
+ Log.w(TAG, "PasswordMetrics is not available");
+ return false;
+ }
+ }
+ }
+
+ /**
* This API is cached; whenever the result would change,
* {@link com.android.internal.widget.LockPatternUtils#invalidateCredentialTypeCache}
* must be called.
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index de3a7ef..731ecad 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -121,6 +121,11 @@
}
@VisibleForTesting
+ public boolean isAutoPinConfirmSettingEnabled(int userId) {
+ return getBoolean(LockPatternUtils.AUTO_PIN_CONFIRM, false, userId);
+ }
+
+ @VisibleForTesting
public void writeKeyValue(SQLiteDatabase db, String key, String value, int userId) {
ContentValues cv = new ContentValues();
cv.put(COLUMN_KEY, key);
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index a4dab72..8b8c5f6 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -16,6 +16,7 @@
package com.android.server.locksettings;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
import static com.android.internal.widget.LockPatternUtils.PIN_LENGTH_UNAVAILABLE;
@@ -545,6 +546,11 @@
return null;
}
+ @VisibleForTesting
+ public boolean isAutoPinConfirmationFeatureAvailable() {
+ return LockPatternUtils.isAutoPinConfirmFeatureAvailable();
+ }
+
private synchronized boolean isWeaverAvailable() {
if (mWeaver != null) {
return true;
@@ -901,8 +907,8 @@
LockscreenCredential credential, SyntheticPassword sp, int userId) {
long protectorId = generateProtectorId();
int pinLength = PIN_LENGTH_UNAVAILABLE;
- if (LockPatternUtils.isAutoPinConfirmFeatureAvailable()) {
- pinLength = derivePinLength(credential, userId);
+ if (isAutoPinConfirmationFeatureAvailable()) {
+ pinLength = derivePinLength(credential.size(), credential.isPin(), userId);
}
// There's no need to store password data about an empty LSKF.
PasswordData pwd = credential.isNone() ? null :
@@ -978,13 +984,13 @@
return protectorId;
}
- private int derivePinLength(LockscreenCredential credential, int userId) {
- if (!credential.isPin()
- || !mStorage.getBoolean(LockPatternUtils.AUTO_PIN_CONFIRM, false, userId)
- || credential.size() < LockPatternUtils.MIN_AUTO_PIN_REQUIREMENT_LENGTH) {
+ private int derivePinLength(int sizeOfCredential, boolean isPinCredential, int userId) {
+ if (!isPinCredential
+ || !mStorage.isAutoPinConfirmSettingEnabled(userId)
+ || sizeOfCredential < LockPatternUtils.MIN_AUTO_PIN_REQUIREMENT_LENGTH) {
return PIN_LENGTH_UNAVAILABLE;
}
- return credential.size();
+ return sizeOfCredential;
}
public VerifyCredentialResponse verifyFrpCredential(IGateKeeperService gatekeeper,
@@ -1347,19 +1353,39 @@
savePasswordMetrics(credential, result.syntheticPassword, protectorId, userId);
syncState(userId); // Not strictly needed as the upgrade can be re-done, but be safe.
}
- if (LockPatternUtils.isAutoPinConfirmFeatureAvailable()
- && result.syntheticPassword != null && pwd != null) {
- int expectedPinLength = derivePinLength(credential, userId);
- if (pwd.pinLength != expectedPinLength) {
- pwd.pinLength = expectedPinLength;
- saveState(PASSWORD_DATA_NAME, pwd.toBytes(), protectorId, userId);
- syncState(userId);
- }
- }
return result;
}
/**
+ * {@link LockPatternUtils#refreshStoredPinLength(int)}
+ * @param passwordMetrics passwordMetrics object containing the cached pin length
+ * @param userId userId of the user whose pin length we want to store on disk
+ * @param protectorId current LSKF based protectorId
+ * @return true/false depending on whether PIN length has been saved on disk
+ */
+ public boolean refreshPinLengthOnDisk(PasswordMetrics passwordMetrics,
+ long protectorId, int userId) {
+ if (!isAutoPinConfirmationFeatureAvailable()) {
+ return false;
+ }
+
+ byte[] pwdDataBytes = loadState(PASSWORD_DATA_NAME, protectorId, userId);
+ if (pwdDataBytes == null) {
+ return false;
+ }
+
+ PasswordData pwd = PasswordData.fromBytes(pwdDataBytes);
+ int pinLength = derivePinLength(passwordMetrics.length,
+ passwordMetrics.credType == CREDENTIAL_TYPE_PIN, userId);
+ if (pwd.pinLength != pinLength) {
+ pwd.pinLength = pinLength;
+ saveState(PASSWORD_DATA_NAME, pwd.toBytes(), protectorId, userId);
+ syncState(userId);
+ }
+ return true;
+ }
+
+ /**
* Tries to unlock a token-based SP protector (weak or strong), given its ID and the claimed
* token. On success, returns the user's synthetic password, and also does a Gatekeeper
* verification to refresh the SID and HardwareAuthToken maintained by the system.
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/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 6f7ce80..1aa1fd1 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -4298,6 +4298,11 @@
if (Process.isSdkSandboxUid(uid)) {
uid = getBaseSdkSandboxUid();
}
+ if (Process.isIsolatedUid(uid)
+ && mPermissionManager.getHotwordDetectionServiceProvider() != null
+ && uid == mPermissionManager.getHotwordDetectionServiceProvider().getUid()) {
+ uid = getIsolatedOwner(uid);
+ }
final int callingUserId = UserHandle.getUserId(callingUid);
final int appId = UserHandle.getAppId(uid);
final Object obj = mSettings.getSettingBase(appId);
@@ -4334,6 +4339,11 @@
if (Process.isSdkSandboxUid(uid)) {
uid = getBaseSdkSandboxUid();
}
+ if (Process.isIsolatedUid(uid)
+ && mPermissionManager.getHotwordDetectionServiceProvider() != null
+ && uid == mPermissionManager.getHotwordDetectionServiceProvider().getUid()) {
+ uid = getIsolatedOwner(uid);
+ }
final int appId = UserHandle.getAppId(uid);
final Object obj = mSettings.getSettingBase(appId);
if (obj instanceof SharedUserSetting) {
diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java
index 9683469..dc5915d 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFilter.java
@@ -37,7 +37,7 @@
Direction.TO_PROFILE
})
@Retention(RetentionPolicy.SOURCE)
- @interface Direction {
+ public @interface Direction {
int TO_PARENT = 0;
int TO_PROFILE = 1;
}
diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
index 9eb73aa..48ee64f 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
@@ -25,6 +25,7 @@
import android.provider.AlarmClock;
import android.provider.MediaStore;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -88,6 +89,23 @@
.addDataType("vnd.android.cursor.item/calls")
.build();
+ /** Dial intent with mime type exclusively handled by managed profile. */
+ private static final DefaultCrossProfileIntentFilter DIAL_MIME_MANAGED_PROFILE =
+ new DefaultCrossProfileIntentFilter.Builder(
+ DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
+ SKIP_CURRENT_PROFILE,
+ /* letsPersonalDataIntoProfile= */ false)
+ .addAction(Intent.ACTION_DIAL)
+ .addAction(Intent.ACTION_VIEW)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .addDataType("vnd.android.cursor.item/phone")
+ .addDataType("vnd.android.cursor.item/phone_v2")
+ .addDataType("vnd.android.cursor.item/person")
+ .addDataType("vnd.android.cursor.dir/calls")
+ .addDataType("vnd.android.cursor.item/calls")
+ .build();
+
/** Dial intent with data scheme can be handled by either managed profile or its parent user. */
private static final DefaultCrossProfileIntentFilter DIAL_DATA =
new DefaultCrossProfileIntentFilter.Builder(
@@ -103,6 +121,21 @@
.addDataScheme("voicemail")
.build();
+ /** Dial intent with data scheme exclusively handled by managed profile. */
+ private static final DefaultCrossProfileIntentFilter DIAL_DATA_MANAGED_PROFILE =
+ new DefaultCrossProfileIntentFilter.Builder(
+ DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
+ SKIP_CURRENT_PROFILE,
+ /* letsPersonalDataIntoProfile= */ false)
+ .addAction(Intent.ACTION_DIAL)
+ .addAction(Intent.ACTION_VIEW)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .addDataScheme("tel")
+ .addDataScheme("sip")
+ .addDataScheme("voicemail")
+ .build();
+
/**
* Dial intent with no data scheme or type can be handled by either managed profile or its
* parent user.
@@ -117,6 +150,19 @@
.addCategory(Intent.CATEGORY_BROWSABLE)
.build();
+ /**
+ * Dial intent with no data scheme or type exclusively handled by managed profile.
+ */
+ private static final DefaultCrossProfileIntentFilter DIAL_RAW_MANAGED_PROFILE =
+ new DefaultCrossProfileIntentFilter.Builder(
+ DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
+ SKIP_CURRENT_PROFILE,
+ /* letsPersonalDataIntoProfile= */ false)
+ .addAction(Intent.ACTION_DIAL)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .build();
+
/** Pressing the call button can be handled by either managed profile or its parent user. */
private static final DefaultCrossProfileIntentFilter CALL_BUTTON =
new DefaultCrossProfileIntentFilter.Builder(
@@ -143,6 +189,22 @@
.addDataScheme("mmsto")
.build();
+ /** SMS and MMS intent exclusively handled by the managed profile. */
+ private static final DefaultCrossProfileIntentFilter SMS_MMS_MANAGED_PROFILE =
+ new DefaultCrossProfileIntentFilter.Builder(
+ DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
+ SKIP_CURRENT_PROFILE,
+ /* letsPersonalDataIntoProfile= */ false)
+ .addAction(Intent.ACTION_VIEW)
+ .addAction(Intent.ACTION_SENDTO)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .addDataScheme("sms")
+ .addDataScheme("smsto")
+ .addDataScheme("mms")
+ .addDataScheme("mmsto")
+ .build();
+
/** Mobile network settings is always shown in the primary user. */
private static final DefaultCrossProfileIntentFilter
MOBILE_NETWORK_SETTINGS =
@@ -297,14 +359,12 @@
.build();
public static List<DefaultCrossProfileIntentFilter> getDefaultManagedProfileFilters() {
- return Arrays.asList(
+ List<DefaultCrossProfileIntentFilter> filters =
+ new ArrayList<DefaultCrossProfileIntentFilter>();
+ filters.addAll(Arrays.asList(
EMERGENCY_CALL_MIME,
EMERGENCY_CALL_DATA,
- DIAL_MIME,
- DIAL_DATA,
- DIAL_RAW,
CALL_BUTTON,
- SMS_MMS,
SET_ALARM,
MEDIA_CAPTURE,
RECOGNIZE_SPEECH,
@@ -317,11 +377,13 @@
USB_DEVICE_ATTACHED,
ACTION_SEND,
HOME,
- MOBILE_NETWORK_SETTINGS);
+ MOBILE_NETWORK_SETTINGS));
+ filters.addAll(getDefaultCrossProfileTelephonyIntentFilters(false));
+ return filters;
}
- /** Call intent with tel scheme */
- private static final DefaultCrossProfileIntentFilter CALL =
+ /** Call intent with tel scheme exclusively handled my managed profile. */
+ private static final DefaultCrossProfileIntentFilter CALL_MANAGED_PROFILE =
new DefaultCrossProfileIntentFilter.Builder(
DefaultCrossProfileIntentFilter.Direction.TO_PROFILE,
SKIP_CURRENT_PROFILE,
@@ -334,13 +396,22 @@
/**
* Returns default telephony related intent filters for managed profile.
*/
- public static List<DefaultCrossProfileIntentFilter> getDefaultManagedProfileTelephonyFilters() {
- return Arrays.asList(
- DIAL_DATA,
- DIAL_MIME,
- DIAL_RAW,
- CALL,
- SMS_MMS);
+ public static List<DefaultCrossProfileIntentFilter>
+ getDefaultCrossProfileTelephonyIntentFilters(boolean telephonyOnlyInManagedProfile) {
+ if (telephonyOnlyInManagedProfile) {
+ return Arrays.asList(
+ DIAL_DATA_MANAGED_PROFILE,
+ DIAL_MIME_MANAGED_PROFILE,
+ DIAL_RAW_MANAGED_PROFILE,
+ CALL_MANAGED_PROFILE,
+ SMS_MMS_MANAGED_PROFILE);
+ } else {
+ return Arrays.asList(
+ DIAL_DATA,
+ DIAL_MIME,
+ DIAL_RAW,
+ SMS_MMS);
+ }
}
/**
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index ad8a9ba..1e0c95c 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -49,6 +49,7 @@
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
+import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_NAME;
import static com.android.server.pm.PackageManagerService.DEBUG_BACKUP;
import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
@@ -497,6 +498,13 @@
mPm.setUpCustomResolverActivity(pkg, pkgSetting);
}
+ File appMetadataFile = new File(pkgSetting.getPath(), APP_METADATA_FILE_NAME);
+ if (appMetadataFile.exists()) {
+ pkgSetting.setAppMetadataFilePath(appMetadataFile.getAbsolutePath());
+ } else {
+ pkgSetting.setAppMetadataFilePath(null);
+ }
+
if (pkg.getPackageName().equals("android")) {
mPm.setPlatformPackage(pkg, pkgSetting);
}
@@ -1135,22 +1143,22 @@
// behavior.
if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
"MinInstallableTargetSdk__install_block_enabled",
- true)) {
+ false)) {
int minInstallableTargetSdk =
DeviceConfig.getInt(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
"MinInstallableTargetSdk__min_installable_target_sdk",
- PackageManagerService.MIN_INSTALLABLE_TARGET_SDK);
+ 0);
// Determine if enforcement is in strict mode
boolean strictMode = false;
if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
"MinInstallableTargetSdk__install_block_strict_mode_enabled",
- true)) {
+ false)) {
if (parsedPackage.getTargetSdkVersion()
< DeviceConfig.getInt(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
"MinInstallableTargetSdk__strict_mode_target_sdk",
- PackageManagerService.MIN_INSTALLABLE_TARGET_SDK)) {
+ 0)) {
strictMode = true;
}
}
@@ -2946,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/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3e1a1ac..b5108af 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -560,14 +560,6 @@
// How many required verifiers can be on the system.
private static final int REQUIRED_VERIFIERS_MAX_COUNT = 2;
- /**
- * Specifies the minimum target SDK version an apk must specify in order to be installed
- * on the system. This improves security and privacy by blocking low
- * target sdk apps as malware can target older sdk versions to avoid
- * the enforcement of new API behavior.
- */
- public static final int MIN_INSTALLABLE_TARGET_SDK = Build.VERSION_CODES.M;
-
// Compilation reasons.
// TODO(b/260124949): Clean this up with the legacy dexopt code.
public static final int REASON_FIRST_BOOT = 0;
@@ -2364,6 +2356,32 @@
SystemClock.uptimeMillis() - startTime);
}
+ // If this is first boot or first boot after OTA then set the file path to the app
+ // metadata files for preloaded packages.
+ if (mFirstBoot || isDeviceUpgrading()) {
+ ArrayMap<String, String> paths = systemConfig.getAppMetadataFilePaths();
+ for (Map.Entry<String, String> entry : paths.entrySet()) {
+ String pkgName = entry.getKey();
+ String path = entry.getValue();
+ File file = new File(path);
+ if (!file.exists()) {
+ path = null;
+ }
+ PackageSetting disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(pkgName);
+ if (disabledPkgSetting == null) {
+ PackageSetting pkgSetting = mSettings.getPackageLPr(pkgName);
+ if (pkgSetting != null) {
+ pkgSetting.setAppMetadataFilePath(path);
+ } else {
+ Slog.w(TAG, "Cannot set app metadata file for nonexistent package "
+ + pkgName);
+ }
+ } else {
+ disabledPkgSetting.setAppMetadataFilePath(path);
+ }
+ }
+ }
+
// Rebuild the live computer since some attributes have been rebuilt.
mLiveComputer = createLiveComputer();
@@ -5164,12 +5182,16 @@
throw new ParcelableException(
new PackageManager.NameNotFoundException(packageName));
}
- try {
- File file = new File(ps.getPath(), APP_METADATA_FILE_NAME);
- return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
- } catch (FileNotFoundException e) {
- return null;
+ String filePath = ps.getAppMetadataFilePath();
+ if (filePath != null) {
+ File file = new File(filePath);
+ try {
+ return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+ } catch (FileNotFoundException e) {
+ return null;
+ }
}
+ return null;
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 89f46fe..eea6720 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -124,10 +124,12 @@
import libcore.io.IoUtils;
import libcore.io.Streams;
+import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URISyntaxException;
@@ -348,6 +350,8 @@
return runDisableVerificationForUid();
case "set-silent-updates-policy":
return runSetSilentUpdatesPolicy();
+ case "get-app-metadata":
+ return runGetAppMetadata();
default: {
if (ART_SERVICE_COMMANDS.contains(cmd)) {
if (DexOptHelper.useArtService()) {
@@ -3541,6 +3545,30 @@
return 1;
}
+ private int runGetAppMetadata() {
+ final PrintWriter pw = getOutPrintWriter();
+ String pkgName = getNextArgRequired();
+ ParcelFileDescriptor pfd = null;
+ try {
+ pfd = mInterface.getAppMetadataFd(pkgName, mContext.getUserId());
+ } catch (RemoteException e) {
+ pw.println("Failure [" + e.getClass().getName() + " - " + e.getMessage() + "]");
+ return -1;
+ }
+ if (pfd != null) {
+ try (BufferedReader br = new BufferedReader(
+ new InputStreamReader(new ParcelFileDescriptor.AutoCloseInputStream(pfd)))) {
+ while (br.ready()) {
+ pw.println(br.readLine());
+ }
+ } catch (IOException e) {
+ pw.println("Failure [" + e.getClass().getName() + " - " + e.getMessage() + "]");
+ return -1;
+ }
+ }
+ return 1;
+ }
+
private int runArtServiceCommand() {
try (var in = ParcelFileDescriptor.dup(getInFileDescriptor());
var out = ParcelFileDescriptor.dup(getOutFileDescriptor());
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 839ff41..7fda092 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -189,6 +189,9 @@
@NonNull
private UUID mDomainSetId;
+ @Nullable
+ private String mAppMetadataFilePath;
+
/**
* Snapshot support.
*/
@@ -655,6 +658,7 @@
updateAvailable = other.updateAvailable;
forceQueryableOverride = other.forceQueryableOverride;
mDomainSetId = other.mDomainSetId;
+ mAppMetadataFilePath = other.mAppMetadataFilePath;
usesSdkLibraries = other.usesSdkLibraries != null
? Arrays.copyOf(other.usesSdkLibraries,
@@ -1171,6 +1175,15 @@
return this;
}
+ /**
+ * @param path to app metadata file
+ */
+ public PackageSetting setAppMetadataFilePath(String path) {
+ mAppMetadataFilePath = path;
+ onChanged();
+ return this;
+ }
+
@NonNull
@Override
public long getVersionCode() {
@@ -1579,11 +1592,16 @@
return mDomainSetId;
}
+ @DataClass.Generated.Member
+ public @Nullable String getAppMetadataFilePath() {
+ return mAppMetadataFilePath;
+ }
+
@DataClass.Generated(
- time = 1678228625853L,
+ time = 1680917079522L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/PackageSetting.java",
- inputSignatures = "private int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackageInternal pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate float mLoadingProgress\nprivate long mLoadingCompletedTime\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate long mLastModifiedTime\nprivate long lastUpdateTime\nprivate long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate int categoryOverride\nprivate boolean updateAvailable\nprivate boolean forceQueryableOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic com.android.server.pm.PackageSetting snapshot()\npublic void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic com.android.server.pm.PackageSetting setAppId(int)\npublic com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic com.android.server.pm.PackageSetting setInstallerPackage(java.lang.String,int)\npublic com.android.server.pm.PackageSetting setUpdateOwnerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPkg(com.android.server.pm.pkg.AndroidPackage)\npublic com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic void setSharedUserAppId(int)\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprotected void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic void updateFrom(com.android.server.pm.PackageSetting)\n com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic boolean isPrivileged()\npublic boolean isOem()\npublic boolean isVendor()\npublic boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic boolean isSystemExt()\npublic boolean isOdm()\npublic boolean isSystem()\npublic android.content.pm.SigningDetails getSigningDetails()\npublic com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic void copyPackageSetting(com.android.server.pm.PackageSetting,boolean)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n void setEnabled(int,int,java.lang.String)\n int getEnabled(int)\n void setInstalled(boolean,int)\n boolean getInstalled(int)\n int getInstallReason(int)\n void setInstallReason(int,int)\n int getUninstallReason(int)\n void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n boolean isAnyInstalled(int[])\n int[] queryInstalledUsers(int[],boolean)\n long getCeDataInode(int)\n void setCeDataInode(long,int)\n boolean getStopped(int)\n void setStopped(boolean,int)\n boolean getNotLaunched(int)\n void setNotLaunched(boolean,int)\n boolean getHidden(int)\n void setHidden(boolean,int)\n int getDistractionFlags(int)\n void setDistractionFlags(int,int)\npublic boolean getInstantApp(int)\n void setInstantApp(boolean,int)\n boolean getVirtualPreload(int)\n void setVirtualPreload(boolean,int)\n void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long)\n void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponents(int)\n com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponents(int)\n void setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setEnabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setDisabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n void addDisabledComponent(java.lang.String,int)\n void addEnabledComponent(java.lang.String,int)\n boolean enableComponentLPw(java.lang.String,int)\n boolean disableComponentLPw(java.lang.String,int)\n boolean restoreComponentLPw(java.lang.String,int)\n int getCurrentEnabledStateLPr(java.lang.String,int)\n void removeUser(int)\npublic int[] getNotInstalledUserIds()\n void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic boolean isIncremental()\npublic boolean isLoading()\npublic com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic com.android.server.pm.PackageSetting setLoadingCompletedTime(long)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackage getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<com.android.server.pm.pkg.SharedLibrary> getSharedLibraryDependencies()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryInfo(android.content.pm.SharedLibraryInfo)\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryFile(java.lang.String)\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getApexModuleName()\npublic com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic com.android.server.pm.PackageSetting setApexModuleName(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserState getStateForUser(android.os.UserHandle)\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbi()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbi()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getSeInfo()\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbiLegacy()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbiLegacy()\npublic @android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy @java.lang.Override int getHiddenApiEnforcementPolicy()\npublic @java.lang.Override boolean isApex()\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
+ inputSignatures = "private int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackageInternal pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate float mLoadingProgress\nprivate long mLoadingCompletedTime\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate long mLastModifiedTime\nprivate long lastUpdateTime\nprivate long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate int categoryOverride\nprivate boolean updateAvailable\nprivate boolean forceQueryableOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate @android.annotation.Nullable java.lang.String mAppMetadataFilePath\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic com.android.server.pm.PackageSetting snapshot()\npublic void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic com.android.server.pm.PackageSetting setAppId(int)\npublic com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic com.android.server.pm.PackageSetting setInstallerPackage(java.lang.String,int)\npublic com.android.server.pm.PackageSetting setUpdateOwnerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPkg(com.android.server.pm.pkg.AndroidPackage)\npublic com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic void setSharedUserAppId(int)\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprotected void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic void updateFrom(com.android.server.pm.PackageSetting)\n com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic boolean isPrivileged()\npublic boolean isOem()\npublic boolean isVendor()\npublic boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic boolean isSystemExt()\npublic boolean isOdm()\npublic boolean isSystem()\npublic android.content.pm.SigningDetails getSigningDetails()\npublic com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic void copyPackageSetting(com.android.server.pm.PackageSetting,boolean)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n void setEnabled(int,int,java.lang.String)\n int getEnabled(int)\n void setInstalled(boolean,int)\n boolean getInstalled(int)\n int getInstallReason(int)\n void setInstallReason(int,int)\n int getUninstallReason(int)\n void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n boolean isAnyInstalled(int[])\n int[] queryInstalledUsers(int[],boolean)\n long getCeDataInode(int)\n void setCeDataInode(long,int)\n boolean getStopped(int)\n void setStopped(boolean,int)\n boolean getNotLaunched(int)\n void setNotLaunched(boolean,int)\n boolean getHidden(int)\n void setHidden(boolean,int)\n int getDistractionFlags(int)\n void setDistractionFlags(int,int)\npublic boolean getInstantApp(int)\n void setInstantApp(boolean,int)\n boolean getVirtualPreload(int)\n void setVirtualPreload(boolean,int)\n void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long)\n void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponents(int)\n com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponents(int)\n void setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setEnabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setDisabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n void addDisabledComponent(java.lang.String,int)\n void addEnabledComponent(java.lang.String,int)\n boolean enableComponentLPw(java.lang.String,int)\n boolean disableComponentLPw(java.lang.String,int)\n boolean restoreComponentLPw(java.lang.String,int)\n int getCurrentEnabledStateLPr(java.lang.String,int)\n void removeUser(int)\npublic int[] getNotInstalledUserIds()\n void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic boolean isIncremental()\npublic boolean isLoading()\npublic com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic com.android.server.pm.PackageSetting setLoadingCompletedTime(long)\npublic com.android.server.pm.PackageSetting setAppMetadataFilePath(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackage getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<com.android.server.pm.pkg.SharedLibrary> getSharedLibraryDependencies()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryInfo(android.content.pm.SharedLibraryInfo)\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryFile(java.lang.String)\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getApexModuleName()\npublic com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic com.android.server.pm.PackageSetting setApexModuleName(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserState getStateForUser(android.os.UserHandle)\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbi()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbi()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getSeInfo()\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbiLegacy()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbiLegacy()\npublic @android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy @java.lang.Override int getHiddenApiEnforcementPolicy()\npublic @java.lang.Override boolean isApex()\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 417ba07..e8f89d3 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2905,6 +2905,11 @@
serializer.attributeLongHex(null, "loadingCompletedTime",
pkg.getLoadingCompletedTime());
+ if (pkg.getAppMetadataFilePath() != null) {
+ serializer.attribute(null, "appMetadataFilePath",
+ pkg.getAppMetadataFilePath());
+ }
+
writeUsesSdkLibLPw(serializer, pkg.getUsesSdkLibraries(),
pkg.getUsesSdkLibrariesVersionsMajor());
@@ -2994,6 +2999,10 @@
serializer.attribute(null, "domainSetId", pkg.getDomainSetId().toString());
+ if (pkg.getAppMetadataFilePath() != null) {
+ serializer.attribute(null, "appMetadataFilePath", pkg.getAppMetadataFilePath());
+ }
+
writeUsesSdkLibLPw(serializer, pkg.getUsesSdkLibraries(),
pkg.getUsesSdkLibrariesVersionsMajor());
@@ -3762,6 +3771,7 @@
float loadingProgress = 0;
long loadingCompletedTime = 0;
UUID domainSetId;
+ String appMetadataFilePath = null;
try {
name = parser.getAttributeValue(null, ATTR_NAME);
realName = parser.getAttributeValue(null, "realName");
@@ -3799,6 +3809,7 @@
volumeUuid = parser.getAttributeValue(null, "volumeUuid");
categoryHint = parser.getAttributeInt(null, "categoryHint",
ApplicationInfo.CATEGORY_UNDEFINED);
+ appMetadataFilePath = parser.getAttributeValue(null, "appMetadataFilePath");
String domainSetIdString = parser.getAttributeValue(null, "domainSetId");
@@ -3942,7 +3953,8 @@
.setUpdateAvailable(updateAvailable)
.setForceQueryableOverride(installedForceQueryable)
.setLoadingProgress(loadingProgress)
- .setLoadingCompletedTime(loadingCompletedTime);
+ .setLoadingCompletedTime(loadingCompletedTime)
+ .setAppMetadataFilePath(appMetadataFilePath);
// Handle legacy string here for single-user mode
final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
if (enabledStr != null) {
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
index 3a0ff27..f839648 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
@@ -105,4 +105,10 @@
*/
@Nullable
String getSecondaryCpuAbiLegacy();
+
+ /**
+ * @return the app metadata file path.
+ */
+ @Nullable
+ String getAppMetadataFilePath();
}
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index e437be8..2007079 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -17,10 +17,12 @@
package com.android.server.rollback;
import android.annotation.AnyThread;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
@@ -68,6 +70,9 @@
final class RollbackPackageHealthObserver implements PackageHealthObserver {
private static final String TAG = "RollbackPackageHealthObserver";
private static final String NAME = "rollback-observer";
+ private static final String PROP_ATTEMPTING_REBOOT = "sys.attempting_reboot";
+ private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
+ | ApplicationInfo.FLAG_SYSTEM;
private final Context mContext;
private final Handler mHandler;
@@ -114,10 +119,10 @@
// For native crashes, we will directly roll back any available rollbacks
// Note: For non-native crashes the rollback-all step has higher impact
impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30;
- } else if (mitigationCount == 1 && getAvailableRollback(failedPackage) != null) {
+ } else if (getAvailableRollback(failedPackage) != null) {
// Rollback is available, we may get a callback into #execute
impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_30;
- } else if (mitigationCount > 1 && anyRollbackAvailable) {
+ } else if (anyRollbackAvailable) {
// If any rollbacks are available, we will commit them
impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_70;
}
@@ -133,14 +138,10 @@
return true;
}
- if (mitigationCount == 1) {
- RollbackInfo rollback = getAvailableRollback(failedPackage);
- if (rollback == null) {
- Slog.w(TAG, "Expected rollback but no valid rollback found for " + failedPackage);
- return false;
- }
+ RollbackInfo rollback = getAvailableRollback(failedPackage);
+ if (rollback != null) {
mHandler.post(() -> rollbackPackage(rollback, failedPackage, rollbackReason));
- } else if (mitigationCount > 1) {
+ } else {
mHandler.post(() -> rollbackAll(rollbackReason));
}
@@ -153,6 +154,30 @@
return NAME;
}
+ @Override
+ public boolean isPersistent() {
+ return true;
+ }
+
+ @Override
+ public boolean mayObservePackage(String packageName) {
+ if (mContext.getSystemService(RollbackManager.class)
+ .getAvailableRollbacks().isEmpty()) {
+ return false;
+ }
+ return isPersistentSystemApp(packageName);
+ }
+
+ private boolean isPersistentSystemApp(@NonNull String packageName) {
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
+ return (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
private void assertInWorkerThread() {
Preconditions.checkState(mHandler.getLooper().isCurrentThread());
}
@@ -425,6 +450,7 @@
markStagedSessionHandled(rollback.getRollbackId());
// Wait for all pending staged sessions to get handled before rebooting.
if (isPendingStagedSessionsEmpty()) {
+ SystemProperties.set(PROP_ATTEMPTING_REBOOT, "true");
mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
}
}
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 433d807..0ce17de 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -21,6 +21,7 @@
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
import static android.hardware.display.HdrConversionMode.HDR_CONVERSION_PASSTHROUGH;
+import static android.hardware.display.HdrConversionMode.HDR_CONVERSION_UNSUPPORTED;
import static android.hardware.graphics.common.Hdr.DOLBY_VISION;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@@ -750,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);
}
@@ -950,6 +953,7 @@
registerPendingIntentsPerPackagePuller();
registerPinnerServiceStats();
registerHdrCapabilitiesPuller();
+ registerCachedAppsHighWatermarkPuller();
}
private void initAndRegisterNetworkStatsPullers() {
@@ -4721,13 +4725,22 @@
boolean userDisabledHdrConversion = hdrConversionMode == HDR_CONVERSION_PASSTHROUGH;
int forceHdrFormat = preferredHdrType == HDR_TYPE_INVALID ? 0 : preferredHdrType;
boolean hasDolbyVisionIssue = hasDolbyVisionIssue(display);
+ byte[] hdrOutputTypes = toBytes(displayManager.getSupportedHdrOutputTypes());
+ boolean hdrOutputControlSupported = hdrConversionMode != HDR_CONVERSION_UNSUPPORTED;
- pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
- new byte[0], userDisabledHdrConversion, forceHdrFormat, hasDolbyVisionIssue));
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, hdrOutputTypes,
+ userDisabledHdrConversion, forceHdrFormat, hasDolbyVisionIssue,
+ hdrOutputControlSupported));
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())
@@ -4773,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/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 1ab7f362..9cf0834 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -124,6 +124,7 @@
private static final Set<Integer> SYSTEM_VIBRATION_SCREEN_OFF_USAGE_ALLOWLIST = new HashSet<>(
Arrays.asList(
USAGE_TOUCH,
+ USAGE_ACCESSIBILITY,
USAGE_PHYSICAL_EMULATION,
USAGE_HARDWARE_FEEDBACK));
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f5cb613..2160ce1 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5315,6 +5315,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/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index 1944b3f..90af4c6 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -23,7 +23,6 @@
import static android.app.PendingIntent.FLAG_ONE_SHOT;
import static android.app.admin.DevicePolicyManager.EXTRA_RESTRICTION;
import static android.app.admin.DevicePolicyManager.POLICY_SUSPEND_PACKAGES;
-import static android.app.sdksandbox.SdkSandboxManager.ACTION_START_SANDBOXED_ACTIVITY;
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.Intent.EXTRA_INTENT;
import static android.content.Intent.EXTRA_PACKAGE_NAME;
@@ -503,8 +502,7 @@
@ActivityInterceptorCallback.OrderedId int orderId,
@NonNull ActivityInterceptorCallback.ActivityInterceptorInfo info) {
if (orderId == MAINLINE_SDK_SANDBOX_ORDER_ID) {
- return info.getIntent() != null && info.getIntent().getAction() != null
- && info.getIntent().getAction().equals(ACTION_START_SANDBOXED_ACTIVITY);
+ return info.getIntent() != null && info.getIntent().isSandboxActivity(mServiceContext);
}
return true;
}
@@ -513,8 +511,7 @@
@ActivityInterceptorCallback.OrderedId int orderId,
@NonNull ActivityInterceptorCallback.ActivityInterceptorInfo info) {
if (orderId == MAINLINE_SDK_SANDBOX_ORDER_ID) {
- return info.getIntent() != null && info.getIntent().getAction() != null
- && info.getIntent().getAction().equals(ACTION_START_SANDBOXED_ACTIVITY);
+ return info.getIntent() != null && info.getIntent().isSandboxActivity(mServiceContext);
}
return true;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 064af0f..abf66bc 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -38,7 +38,6 @@
import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.sdksandbox.SdkSandboxManager.ACTION_START_SANDBOXED_ACTIVITY;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
@@ -1244,9 +1243,7 @@
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
- boolean isSandboxedActivity = (intent != null && intent.getAction() != null
- && intent.getAction().equals(ACTION_START_SANDBOXED_ACTIVITY));
- if (isSandboxedActivity) {
+ if (intent != null && intent.isSandboxActivity(mContext)) {
SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
SdkSandboxManagerLocal.class);
sdkSandboxManagerLocal.enforceAllowedToHostSandboxedActivity(
@@ -1503,7 +1500,7 @@
.setCallingPid(callingPid)
.setCallingPackage(intent.getPackage())
.setActivityInfo(a)
- .setActivityOptions(options.toBundle())
+ .setActivityOptions(createSafeActivityOptionsWithBalAllowed(options))
// To start the dream from background, we need to start it from a persistent
// system process. Here we set the real calling uid to the system server uid
.setRealCallingUid(Binder.getCallingUid())
@@ -1651,7 +1648,7 @@
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
- .setActivityOptions(bOptions)
+ .setActivityOptions(createSafeActivityOptionsWithBalAllowed(bOptions))
.setUserId(userId)
.setIgnoreTargetSecurity(ignoreTargetSecurity)
.setFilterCallingUid(isResolver ? 0 /* system */ : targetUid)
@@ -1701,7 +1698,7 @@
.setVoiceInteractor(interactor)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
- .setActivityOptions(bOptions)
+ .setActivityOptions(createSafeActivityOptionsWithBalAllowed(bOptions))
.setUserId(userId)
.setBackgroundStartPrivileges(BackgroundStartPrivileges.ALLOW_BAL)
.execute();
@@ -1728,7 +1725,7 @@
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
- .setActivityOptions(bOptions)
+ .setActivityOptions(createSafeActivityOptionsWithBalAllowed(bOptions))
.setUserId(userId)
.setBackgroundStartPrivileges(BackgroundStartPrivileges.ALLOW_BAL)
.execute();
@@ -5356,7 +5353,7 @@
if (app != null && app.getPid() > 0) {
ArrayList<Integer> firstPids = new ArrayList<Integer>();
firstPids.add(app.getPid());
- dumpStackTraces(tracesFile.getAbsolutePath(), firstPids, null, null, null);
+ dumpStackTraces(tracesFile.getAbsolutePath(), firstPids, null, null, null, null);
}
File lastTracesFile = null;
@@ -5507,6 +5504,31 @@
return checkPermission(permission, -1, sourceUid) == PackageManager.PERMISSION_GRANTED;
}
+ /**
+ * Wrap the {@link ActivityOptions} in {@link SafeActivityOptions} and attach caller options
+ * that allow using the callers permissions to start background activities.
+ */
+ private SafeActivityOptions createSafeActivityOptionsWithBalAllowed(
+ @Nullable ActivityOptions options) {
+ if (options == null) {
+ options = ActivityOptions.makeBasic().setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ } else if (options.getPendingIntentBackgroundActivityStartMode()
+ == ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED) {
+ options.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ }
+ return new SafeActivityOptions(options);
+ }
+
+ /**
+ * Wrap the options {@link Bundle} in {@link SafeActivityOptions} and attach caller options
+ * that allow using the callers permissions to start background activities.
+ */
+ private SafeActivityOptions createSafeActivityOptionsWithBalAllowed(@Nullable Bundle bOptions) {
+ return createSafeActivityOptionsWithBalAllowed(ActivityOptions.fromBundle(bOptions));
+ }
+
final class H extends Handler {
static final int REPORT_TIME_TRACKER_MSG = 1;
static final int UPDATE_PROCESS_ANIMATING_STATE = 2;
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index a83a033..3dc3be9 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -135,12 +135,6 @@
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register display organizer=%s uid=%d",
organizer.asBinder(), uid);
if (mOrganizersByFeatureIds.get(feature) != null) {
- if (mOrganizersByFeatureIds.get(feature).mOrganizer.asBinder()
- .isBinderAlive()) {
- throw new IllegalStateException(
- "Replacing existing organizer currently unsupported");
- }
-
mOrganizersByFeatureIds.remove(feature).destroy();
Slog.d(TAG, "Replacing dead organizer for feature=" + feature);
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 6ed2025..339b6ec 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -128,7 +128,7 @@
import com.android.internal.statusbar.LetterboxDetails;
import com.android.internal.util.ScreenshotHelper;
import com.android.internal.util.ScreenshotRequest;
-import com.android.internal.util.function.TriConsumer;
+import com.android.internal.util.function.TriFunction;
import com.android.internal.view.AppearanceRegion;
import com.android.internal.widget.PointerLocationView;
import com.android.server.LocalServices;
@@ -1081,11 +1081,11 @@
// The index of the provider and corresponding insets types cannot change at
// runtime as ensured in WMS. Make use of the index in the provider directly
// to access the latest provided size at runtime.
- final TriConsumer<DisplayFrames, WindowContainer, Rect> frameProvider =
+ final TriFunction<DisplayFrames, WindowContainer, Rect, Integer> frameProvider =
getFrameProvider(win, i, INSETS_OVERRIDE_INDEX_INVALID);
final InsetsFrameProvider.InsetsSizeOverride[] overrides =
provider.getInsetsSizeOverrides();
- final SparseArray<TriConsumer<DisplayFrames, WindowContainer, Rect>>
+ final SparseArray<TriFunction<DisplayFrames, WindowContainer, Rect, Integer>>
overrideProviders;
if (overrides != null) {
overrideProviders = new SparseArray<>();
@@ -1106,7 +1106,7 @@
}
}
- private static TriConsumer<DisplayFrames, WindowContainer, Rect> getFrameProvider(
+ private static TriFunction<DisplayFrames, WindowContainer, Rect, Integer> getFrameProvider(
WindowState win, int index, int overrideIndex) {
return (displayFrames, windowContainer, inOutFrame) -> {
final LayoutParams lp = win.mAttrs.forRotation(displayFrames.mRotation);
@@ -1152,6 +1152,7 @@
inOutFrame.set(sTmpRect2);
}
}
+ return ifp.getFlags();
};
}
@@ -1179,7 +1180,7 @@
}
}
- TriConsumer<DisplayFrames, WindowContainer, Rect> getImeSourceFrameProvider() {
+ TriFunction<DisplayFrames, WindowContainer, Rect, Integer> getImeSourceFrameProvider() {
return (displayFrames, windowContainer, inOutFrame) -> {
WindowState windowState = windowContainer.asWindowState();
if (windowState == null) {
@@ -1198,6 +1199,7 @@
} else {
inOutFrame.inset(windowState.mGivenContentInsets);
}
+ return 0;
};
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 3e03b99..b7eaf25 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -47,7 +47,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
-import com.android.internal.util.function.TriConsumer;
+import com.android.internal.util.function.TriFunction;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
@@ -73,8 +73,9 @@
private @Nullable InsetsControlTarget mFakeControlTarget;
private @Nullable ControlAdapter mAdapter;
- private TriConsumer<DisplayFrames, WindowContainer, Rect> mFrameProvider;
- private SparseArray<TriConsumer<DisplayFrames, WindowContainer, Rect>> mOverrideFrameProviders;
+ private TriFunction<DisplayFrames, WindowContainer, Rect, Integer> mFrameProvider;
+ private SparseArray<TriFunction<DisplayFrames, WindowContainer, Rect, Integer>>
+ mOverrideFrameProviders;
private final SparseArray<Rect> mOverrideFrames = new SparseArray<Rect>();
private boolean mIsLeashReadyForDispatching;
private final Rect mSourceFrame = new Rect();
@@ -149,8 +150,8 @@
* resulting frame that should be reported to given window type.
*/
void setWindowContainer(@Nullable WindowContainer windowContainer,
- @Nullable TriConsumer<DisplayFrames, WindowContainer, Rect> frameProvider,
- @Nullable SparseArray<TriConsumer<DisplayFrames, WindowContainer, Rect>>
+ @Nullable TriFunction<DisplayFrames, WindowContainer, Rect, Integer> frameProvider,
+ @Nullable SparseArray<TriFunction<DisplayFrames, WindowContainer, Rect, Integer>>
overrideFrameProviders) {
if (mWindowContainer != null) {
if (mControllable) {
@@ -203,7 +204,7 @@
if (mServerVisible) {
mTmpRect.set(mWindowContainer.getBounds());
if (mFrameProvider != null) {
- mFrameProvider.accept(mWindowContainer.getDisplayContent().mDisplayFrames,
+ mFrameProvider.apply(mWindowContainer.getDisplayContent().mDisplayFrames,
mWindowContainer, mTmpRect);
}
} else {
@@ -216,8 +217,11 @@
mSourceFrame.set(frame);
if (mFrameProvider != null) {
- mFrameProvider.accept(mWindowContainer.getDisplayContent().mDisplayFrames,
- mWindowContainer, mSourceFrame);
+ final int flags = mFrameProvider.apply(
+ mWindowContainer.getDisplayContent().mDisplayFrames,
+ mWindowContainer,
+ mSourceFrame);
+ mSource.setFlags(flags);
}
updateSourceFrameForServerVisibility();
@@ -233,10 +237,10 @@
} else {
overrideFrame = new Rect(frame);
}
- final TriConsumer<DisplayFrames, WindowContainer, Rect> provider =
+ final TriFunction<DisplayFrames, WindowContainer, Rect, Integer> provider =
mOverrideFrameProviders.get(windowType);
if (provider != null) {
- mOverrideFrameProviders.get(windowType).accept(
+ mOverrideFrameProviders.get(windowType).apply(
mWindowContainer.getDisplayContent().mDisplayFrames, mWindowContainer,
overrideFrame);
}
@@ -274,7 +278,7 @@
source.setVisible(mSource.isVisible());
mTmpRect.set(frame);
if (mFrameProvider != null) {
- mFrameProvider.accept(displayFrames, mWindowContainer, mTmpRect);
+ mFrameProvider.apply(displayFrames, mWindowContainer, mTmpRect);
}
source.setFrame(mTmpRect);
return source;
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/TaskFpsCallbackController.java b/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
index c099628..8c79875 100644
--- a/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
+++ b/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
@@ -26,8 +26,8 @@
final class TaskFpsCallbackController {
private final Context mContext;
- private final HashMap<ITaskFpsCallback, Long> mTaskFpsCallbacks;
- private final HashMap<ITaskFpsCallback, IBinder.DeathRecipient> mDeathRecipients;
+ private final HashMap<IBinder, Long> mTaskFpsCallbacks;
+ private final HashMap<IBinder, IBinder.DeathRecipient> mDeathRecipients;
TaskFpsCallbackController(Context context) {
mContext = context;
@@ -36,32 +36,42 @@
}
void registerListener(int taskId, ITaskFpsCallback callback) {
- if (mTaskFpsCallbacks.containsKey(callback)) {
+ if (callback == null) {
+ return;
+ }
+
+ IBinder binder = callback.asBinder();
+ if (mTaskFpsCallbacks.containsKey(binder)) {
return;
}
final long nativeListener = nativeRegister(callback, taskId);
- mTaskFpsCallbacks.put(callback, nativeListener);
+ mTaskFpsCallbacks.put(binder, nativeListener);
final IBinder.DeathRecipient deathRecipient = () -> unregisterListener(callback);
try {
- callback.asBinder().linkToDeath(deathRecipient, 0);
- mDeathRecipients.put(callback, deathRecipient);
+ binder.linkToDeath(deathRecipient, 0);
+ mDeathRecipients.put(binder, deathRecipient);
} catch (RemoteException e) {
// ignore
}
}
void unregisterListener(ITaskFpsCallback callback) {
- if (!mTaskFpsCallbacks.containsKey(callback)) {
+ if (callback == null) {
return;
}
- callback.asBinder().unlinkToDeath(mDeathRecipients.get(callback), 0);
- mDeathRecipients.remove(callback);
+ IBinder binder = callback.asBinder();
+ if (!mTaskFpsCallbacks.containsKey(binder)) {
+ return;
+ }
- nativeUnregister(mTaskFpsCallbacks.get(callback));
- mTaskFpsCallbacks.remove(callback);
+ binder.unlinkToDeath(mDeathRecipients.get(binder), 0);
+ mDeathRecipients.remove(binder);
+
+ nativeUnregister(mTaskFpsCallbacks.get(binder));
+ mTaskFpsCallbacks.remove(binder);
}
private static native long nativeRegister(ITaskFpsCallback callback, int taskId);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8fecf11..99d0ea8 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8526,6 +8526,14 @@
// while in overview
return;
}
+ final WindowState w = t.getWindowState();
+ if (w != null) {
+ final Task task = w.getTask();
+ if (task != null && w.mTransitionController.isTransientHide(task)) {
+ // Don't disturb transient animation by accident touch.
+ return;
+ }
+ }
ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "onPointerDownOutsideFocusLocked called on %s",
t);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 482e172..678d4c8 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5336,6 +5336,17 @@
&& imeTarget.compareTo(this) <= 0;
return inTokenWithAndAboveImeTarget;
}
+
+ // The condition is for the system dialog not belonging to any Activity.
+ // (^FLAG_NOT_FOCUSABLE & FLAG_ALT_FOCUSABLE_IM) means the dialog is still focusable but
+ // should be placed above the IME window.
+ if ((mAttrs.flags & (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM))
+ == FLAG_ALT_FOCUSABLE_IM && isTrustedOverlay() && canAddInternalSystemWindow()) {
+ // Check the current IME target so that it does not lift this window above the IME if
+ // the Z-order of the current IME layering target is greater than it.
+ final WindowState imeTarget = getImeLayeringTarget();
+ return imeTarget != null && imeTarget != this && imeTarget.compareTo(this) <= 0;
+ }
return false;
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index b01d08c..439ad76 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -485,17 +485,7 @@
}
dump += "\n";
- mInputManager->getReader().dump(dump);
- dump += "\n";
-
- mInputManager->getBlocker().dump(dump);
- dump += "\n";
-
- mInputManager->getProcessor().dump(dump);
- dump += "\n";
-
- mInputManager->getDispatcher().dump(dump);
- dump += "\n";
+ mInputManager->dump(dump);
}
bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
@@ -760,7 +750,6 @@
void NativeInputManager::notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) {
ATRACE_CALL();
- mInputManager->getBlocker().notifyInputDevicesChanged(inputDevices);
JNIEnv* env = jniEnv();
size_t count = inputDevices.size();
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 5cad4e2..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);
}
}
@@ -7711,30 +7724,72 @@
private void updateTelephonyCrossProfileIntentFilters(int parentUserId, int profileUserId,
boolean enableWorkTelephony) {
try {
- String packageName = mContext.getOpPackageName();
- if (enableWorkTelephony) {
- // Reset call/sms cross profile intent filters to be handled by managed profile.
- for (DefaultCrossProfileIntentFilter filter :
- DefaultCrossProfileIntentFiltersUtils
- .getDefaultManagedProfileTelephonyFilters()) {
- IntentFilter intentFilter = filter.filter.getIntentFilter();
- if (!mIPackageManager.removeCrossProfileIntentFilter(intentFilter, packageName,
- profileUserId, parentUserId, filter.flags)) {
- Slogf.w(LOG_TAG,
- "Failed to remove cross-profile intent filter: " + intentFilter);
- }
-
- mIPackageManager.addCrossProfileIntentFilter(intentFilter, packageName,
- parentUserId, profileUserId, PackageManager.SKIP_CURRENT_PROFILE);
+ // This should only occur when managed profile is being removed.
+ if (!enableWorkTelephony && profileUserId == UserHandle.USER_NULL) {
+ mIPackageManager.clearCrossProfileIntentFilters(parentUserId,
+ mContext.getPackageName());
+ return;
+ }
+ for (DefaultCrossProfileIntentFilter filter :
+ DefaultCrossProfileIntentFiltersUtils
+ .getDefaultCrossProfileTelephonyIntentFilters(!enableWorkTelephony)) {
+ if (removeCrossProfileIntentFilter(filter, parentUserId, profileUserId)) {
+ Slogf.w(LOG_TAG,
+ "Failed to remove cross-profile intent filter: "
+ + filter.filter.getIntentFilter() + ", enableWorkTelephony: "
+ + enableWorkTelephony);
}
- } else {
- mIPackageManager.clearCrossProfileIntentFilters(parentUserId, packageName);
+ }
+ for (DefaultCrossProfileIntentFilter filter :
+ DefaultCrossProfileIntentFiltersUtils
+ .getDefaultCrossProfileTelephonyIntentFilters(enableWorkTelephony)) {
+ addCrossProfileIntentFilter(filter, parentUserId, profileUserId);
}
} catch (RemoteException re) {
Slogf.wtf(LOG_TAG, "Error updating telephony cross profile intent filters", re);
}
}
+ void addCrossProfileIntentFilter(DefaultCrossProfileIntentFilter filter, int parentUserId,
+ int profileUserId)
+ throws RemoteException {
+ if (filter.direction == DefaultCrossProfileIntentFilter.Direction.TO_PROFILE) {
+ mIPackageManager.addCrossProfileIntentFilter(
+ filter.filter.getIntentFilter(),
+ mContext.getOpPackageName(),
+ parentUserId,
+ profileUserId,
+ filter.flags);
+ } else {
+ mIPackageManager.addCrossProfileIntentFilter(
+ filter.filter.getIntentFilter(),
+ mContext.getOpPackageName(),
+ profileUserId,
+ parentUserId,
+ filter.flags);
+ }
+ }
+
+ boolean removeCrossProfileIntentFilter(DefaultCrossProfileIntentFilter filter, int parentUserId,
+ int profileUserId)
+ throws RemoteException {
+ if (filter.direction == DefaultCrossProfileIntentFilter.Direction.TO_PROFILE) {
+ return mIPackageManager.removeCrossProfileIntentFilter(
+ filter.filter.getIntentFilter(),
+ mContext.getOpPackageName(),
+ parentUserId,
+ profileUserId,
+ filter.flags);
+ } else {
+ return mIPackageManager.removeCrossProfileIntentFilter(
+ filter.filter.getIntentFilter(),
+ mContext.getOpPackageName(),
+ profileUserId,
+ parentUserId,
+ filter.flags);
+ }
+ }
+
/**
* @param factoryReset null: legacy behaviour, false: attempt to remove user, true: attempt to
* factory reset
@@ -9515,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);
@@ -10204,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);
@@ -10994,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) {
@@ -11009,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();
@@ -11047,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);
}
@@ -13978,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
@@ -14004,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());
}
}
@@ -14028,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
@@ -14637,7 +14729,7 @@
if (isPolicyEngineForFinanceFlagEnabled()) {
EnforcingAdmin enforcingAdmin;
synchronized (getLockObject()) {
- enforcingAdmin = enforceCanCallLockTaskLocked(who, callerPackageName);
+ enforcingAdmin = enforceCanCallLockTaskLocked(who, caller.getPackageName());
}
if (packages.length == 0) {
mDevicePolicyEngine.removeLocalPolicy(
@@ -14764,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(
@@ -14842,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");
@@ -18305,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}.
@@ -18342,7 +18454,7 @@
}
}
- boolean compatible = !hasIncompatibleAccounts(am, accounts);
+ boolean compatible = !hasIncompatibleAccounts(userId);
if (compatible) {
Slogf.w(LOG_TAG, "All accounts are compatible");
} else {
@@ -18352,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);
@@ -22214,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;
@@ -22474,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(
@@ -22632,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,
@@ -22657,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}.
*/
@@ -22670,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<>();
{
@@ -22682,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);
@@ -22689,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<>();
@@ -23066,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)) {
@@ -23151,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,
@@ -23346,14 +23542,16 @@
applyManagedSubscriptionsPolicyIfRequired();
int policyType = getManagedSubscriptionsPolicy().getPolicyType();
- if (policyType == ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS) {
- final long id = mInjector.binderClearCallingIdentity();
- try {
+ final long id = mInjector.binderClearCallingIdentity();
+ try {
+ if (policyType == ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS) {
installOemDefaultDialerAndSmsApp(caller.getUserId());
updateTelephonyCrossProfileIntentFilters(parentUserId, caller.getUserId(), true);
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
+ } else if (policyType == ManagedSubscriptionsPolicy.TYPE_ALL_PERSONAL_SUBSCRIPTIONS) {
+ updateTelephonyCrossProfileIntentFilters(parentUserId, caller.getUserId(), false);
}
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
}
}
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/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
index bb3a476..90691a7 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
@@ -34,6 +34,7 @@
import android.app.ActivityManagerInternal;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
+import android.content.res.Configuration;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.IInputManager;
import android.hardware.input.InputManagerGlobal;
@@ -121,6 +122,7 @@
protected IInputMethodInvoker mMockInputMethodInvoker;
protected InputMethodManagerService mInputMethodManagerService;
protected ServiceThread mServiceThread;
+ protected boolean mIsLargeScreen;
@BeforeClass
public static void setupClass() {
@@ -145,6 +147,8 @@
spyOn(mContext);
mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+ mIsLargeScreen = mContext.getResources().getConfiguration()
+ .isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
mCallingUserId = UserHandle.getCallingUserId();
mEditorInfo = new EditorInfo();
mEditorInfo.packageName = TEST_EDITOR_PKG_NAME;
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java
index c6b355c..cea65b5 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java
@@ -124,7 +124,8 @@
switch (mSoftInputState) {
case SOFT_INPUT_STATE_UNSPECIFIED:
- boolean showSoftInput = mSoftInputAdjustment == SOFT_INPUT_ADJUST_RESIZE;
+ boolean showSoftInput =
+ (mSoftInputAdjustment == SOFT_INPUT_ADJUST_RESIZE) || mIsLargeScreen;
verifyShowSoftInput(
showSoftInput /* setVisible */, showSoftInput /* showSoftInput */);
// Soft input was hidden by default, so it doesn't need to call
@@ -165,7 +166,8 @@
switch (mSoftInputState) {
case SOFT_INPUT_STATE_UNSPECIFIED:
- boolean hideSoftInput = mSoftInputAdjustment != SOFT_INPUT_ADJUST_RESIZE;
+ boolean hideSoftInput =
+ (mSoftInputAdjustment != SOFT_INPUT_ADJUST_RESIZE) && !mIsLargeScreen;
verifyShowSoftInput(false /* setVisible */, false /* showSoftInput */);
// Soft input was hidden by default, so it doesn't need to call
// {@code IMS#hideSoftInput()}.
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/WakelockControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/WakelockControllerTest.java
index 07a81ff..c23d4b1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/WakelockControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/WakelockControllerTest.java
@@ -244,6 +244,15 @@
verifyZeroInteractions(mDisplayPowerCallbacks);
}
+ @Test
+ public void testReleaseAll() throws Exception {
+ // Use WAKE_LOCK_MAX to verify it has been correctly set and used in releaseAll().
+ verifyWakelockAcquisition(WakelockController.WAKE_LOCK_MAX,
+ () -> mWakelockController.hasUnfinishedBusiness());
+ mWakelockController.releaseAll();
+ assertFalse(mWakelockController.hasUnfinishedBusiness());
+ }
+
private void verifyWakelockAcquisitionAndReaquisition(int wakelockId,
Callable<Boolean> isWakelockAcquiredCallable)
throws Exception {
@@ -284,6 +293,4 @@
assertFalse(mWakelockController.releaseWakelock(wakelockId));
assertFalse(isWakelockAcquiredCallable.call());
}
-
-
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 06ba5dd..931a2bf 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -308,6 +308,7 @@
whenever(mocks.systemConfig.sharedLibraries).thenReturn(DEFAULT_SHARED_LIBRARIES_LIST)
whenever(mocks.systemConfig.defaultVrComponents).thenReturn(ArraySet())
whenever(mocks.systemConfig.hiddenApiWhitelistedApps).thenReturn(ArraySet())
+ whenever(mocks.systemConfig.appMetadataFilePaths).thenReturn(ArrayMap())
wheneverStatic { SystemProperties.set(anyString(), anyString()) }.thenDoNothing()
wheneverStatic { SystemProperties.getBoolean("fw.free_cache_v2", true) }.thenReturn(true)
wheneverStatic { Environment.getApexDirectory() }.thenReturn(apexDirectory)
diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
index 541b077..a140730 100644
--- a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
@@ -21,10 +21,14 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.RollbackInfo;
@@ -71,9 +75,12 @@
RollbackInfo mRollbackInfo;
@Mock
PackageRollbackInfo mPackageRollbackInfo;
+ @Mock
+ PackageManager mMockPackageManager;
private MockitoSession mSession;
private static final String APP_A = "com.package.a";
+ private static final String APP_B = "com.package.b";
private static final long VERSION_CODE = 1L;
private static final String LOG_TAG = "RollbackPackageHealthObserverTest";
@@ -116,7 +123,7 @@
RollbackPackageHealthObserver observer =
spy(new RollbackPackageHealthObserver(mMockContext));
VersionedPackage testFailedPackage = new VersionedPackage(APP_A, VERSION_CODE);
-
+ VersionedPackage secondFailedPackage = new VersionedPackage(APP_B, VERSION_CODE);
when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
@@ -137,13 +144,16 @@
assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_30,
observer.onHealthCheckFailed(null,
PackageWatchdog.FAILURE_REASON_NATIVE_CRASH, 1));
- // non-native crash
+ // non-native crash for the package
assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_30,
observer.onHealthCheckFailed(testFailedPackage,
PackageWatchdog.FAILURE_REASON_APP_CRASH, 1));
- // Second non-native crash again
+ // non-native crash for a different package
assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_70,
- observer.onHealthCheckFailed(testFailedPackage,
+ observer.onHealthCheckFailed(secondFailedPackage,
+ PackageWatchdog.FAILURE_REASON_APP_CRASH, 1));
+ assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_70,
+ observer.onHealthCheckFailed(secondFailedPackage,
PackageWatchdog.FAILURE_REASON_APP_CRASH, 2));
// Subsequent crashes when rollbacks have completed
when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of());
@@ -152,6 +162,51 @@
PackageWatchdog.FAILURE_REASON_APP_CRASH, 3));
}
+ @Test
+ public void testIsPersistent() {
+ RollbackPackageHealthObserver observer =
+ spy(new RollbackPackageHealthObserver(mMockContext));
+ assertTrue(observer.isPersistent());
+ }
+
+ @Test
+ public void testMayObservePackage_withoutAnyRollback() {
+ RollbackPackageHealthObserver observer =
+ spy(new RollbackPackageHealthObserver(mMockContext));
+ when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of());
+ assertFalse(observer.mayObservePackage(APP_A));
+ }
+
+ @Test
+ public void testMayObservePackage_forPersistentApp()
+ throws PackageManager.NameNotFoundException {
+ RollbackPackageHealthObserver observer =
+ spy(new RollbackPackageHealthObserver(mMockContext));
+ ApplicationInfo info = new ApplicationInfo();
+ info.flags = ApplicationInfo.FLAG_PERSISTENT | ApplicationInfo.FLAG_SYSTEM;
+ when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(mRollbackInfo));
+ when(mRollbackInfo.getPackages()).thenReturn(List.of(mPackageRollbackInfo));
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ when(mMockPackageManager.getApplicationInfo(APP_A, 0)).thenReturn(info);
+ assertTrue(observer.mayObservePackage(APP_A));
+ }
+
+ @Test
+ public void testMayObservePackage_forNonPersistentApp()
+ throws PackageManager.NameNotFoundException {
+ RollbackPackageHealthObserver observer =
+ spy(new RollbackPackageHealthObserver(mMockContext));
+ when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+ when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(mRollbackInfo));
+ when(mRollbackInfo.getPackages()).thenReturn(List.of(mPackageRollbackInfo));
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ when(mMockPackageManager.getApplicationInfo(APP_A, 0))
+ .thenThrow(new PackageManager.NameNotFoundException());
+ assertFalse(observer.mayObservePackage(APP_A));
+ }
+
/**
* Test that isAutomaticRollbackDenied works correctly when packages that are not
* denied are sent.
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/servicestests/src/com/android/server/am/AnrHelperTest.java b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
index 9578993..acdfee9 100644
--- a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
@@ -26,6 +26,7 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
@@ -48,8 +49,10 @@
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
@@ -63,8 +66,9 @@
private AnrHelper mAnrHelper;
private ProcessRecord mAnrApp;
- private ExecutorService mExecutorService;
+ private ExecutorService mAuxExecutorService;
+ private Future<File> mEarlyDumpFuture;
@Rule
public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
@@ -91,9 +95,12 @@
return mServiceThreadRule.getThread().getThreadHandler();
}
}, mServiceThreadRule.getThread());
- mExecutorService = mock(ExecutorService.class);
+ mAuxExecutorService = mock(ExecutorService.class);
+ final ExecutorService earlyDumpExecutorService = mock(ExecutorService.class);
+ mEarlyDumpFuture = mock(Future.class);
+ doReturn(mEarlyDumpFuture).when(earlyDumpExecutorService).submit(any(Callable.class));
- mAnrHelper = new AnrHelper(service, mExecutorService);
+ mAnrHelper = new AnrHelper(service, mAuxExecutorService, earlyDumpExecutorService);
});
}
@@ -125,8 +132,8 @@
verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS)).appNotResponding(
eq(activityShortComponentName), eq(appInfo), eq(parentShortComponentName),
- eq(parentProcess), eq(aboveSystem), eq(timeoutRecord), eq(mExecutorService),
- eq(false) /* onlyDumpSelf */, eq(false) /*isContinuousAnr*/);
+ eq(parentProcess), eq(aboveSystem), eq(timeoutRecord), eq(mAuxExecutorService),
+ eq(false) /* onlyDumpSelf */, eq(false) /*isContinuousAnr*/, eq(mEarlyDumpFuture));
}
@Test
@@ -139,7 +146,7 @@
processingLatch.await();
return null;
}).when(mAnrApp.mErrorState).appNotResponding(anyString(), any(), any(), any(),
- anyBoolean(), any(), any(), anyBoolean(), anyBoolean());
+ anyBoolean(), any(), any(), anyBoolean(), anyBoolean(), any());
final ApplicationInfo appInfo = new ApplicationInfo();
final TimeoutRecord timeoutRecord = TimeoutRecord.forInputDispatchWindowUnresponsive(
"annotation");
@@ -162,7 +169,7 @@
processingLatch.countDown();
// There is only one ANR reported.
verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS).only()).appNotResponding(
- anyString(), any(), any(), any(), anyBoolean(), any(), eq(mExecutorService),
- anyBoolean(), anyBoolean());
+ anyString(), any(), any(), any(), anyBoolean(), any(), eq(mAuxExecutorService),
+ anyBoolean(), anyBoolean(), any());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java
index 6350e22..d92b9f8 100644
--- a/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ProcessRecordTests.java
@@ -203,6 +203,6 @@
processErrorState.appNotResponding(null /* activityShortComponentName */, null /* aInfo */,
null /* parentShortComponentName */, null /* parentProcess */,
false /* aboveSystem */, timeoutRecord, mExecutorService, false /* onlyDumpSelf */,
- false /*isContinuousAnr*/);
+ false /*isContinuousAnr*/, null);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthResultCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthResultCoordinatorTest.java
index ebf7fd8..2102b09 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthResultCoordinatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthResultCoordinatorTest.java
@@ -17,7 +17,8 @@
package com.android.server.biometrics.sensors;
import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_DEFAULT;
-import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_LOCKED;
+import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_PERMANENT_LOCKED;
+import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_TIMED_LOCKED;
import static com.android.server.biometrics.sensors.AuthResultCoordinator.AUTHENTICATOR_UNLOCKED;
import static com.google.common.truth.Truth.assertThat;
@@ -76,7 +77,22 @@
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
AUTHENTICATOR_DEFAULT);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
- AUTHENTICATOR_LOCKED);
+ AUTHENTICATOR_PERMANENT_LOCKED);
+ }
+
+ @Test
+ public void testConvenientLockoutTimed() {
+ mAuthResultCoordinator.lockOutTimed(
+ BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE);
+
+ final Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
+
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
+ AUTHENTICATOR_DEFAULT);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
+ AUTHENTICATOR_DEFAULT);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
+ AUTHENTICATOR_TIMED_LOCKED);
}
@Test
@@ -97,16 +113,31 @@
@Test
public void testWeakLockout() {
mAuthResultCoordinator.lockedOutFor(
- BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE);
+ BiometricManager.Authenticators.BIOMETRIC_WEAK);
Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
AUTHENTICATOR_DEFAULT);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
- AUTHENTICATOR_DEFAULT);
+ AUTHENTICATOR_PERMANENT_LOCKED);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
- AUTHENTICATOR_LOCKED);
+ AUTHENTICATOR_PERMANENT_LOCKED);
+ }
+
+ @Test
+ public void testWeakLockoutTimed() {
+ mAuthResultCoordinator.lockOutTimed(
+ BiometricManager.Authenticators.BIOMETRIC_WEAK);
+
+ Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
+
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
+ AUTHENTICATOR_DEFAULT);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
+ AUTHENTICATOR_TIMED_LOCKED);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
+ AUTHENTICATOR_TIMED_LOCKED);
}
@Test
@@ -132,13 +163,27 @@
Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
- AUTHENTICATOR_LOCKED);
+ AUTHENTICATOR_PERMANENT_LOCKED);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
- AUTHENTICATOR_LOCKED);
+ AUTHENTICATOR_PERMANENT_LOCKED);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
- AUTHENTICATOR_LOCKED);
+ AUTHENTICATOR_PERMANENT_LOCKED);
}
+ @Test
+ public void testStrongLockoutTimed() {
+ mAuthResultCoordinator.lockOutTimed(
+ BiometricManager.Authenticators.BIOMETRIC_STRONG);
+
+ Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
+
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
+ AUTHENTICATOR_TIMED_LOCKED);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
+ AUTHENTICATOR_TIMED_LOCKED);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
+ AUTHENTICATOR_TIMED_LOCKED);
+ }
@Test
public void testStrongUnlock() {
@@ -167,10 +212,30 @@
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)).isEqualTo(
AUTHENTICATOR_DEFAULT);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)).isEqualTo(
- AUTHENTICATOR_LOCKED);
+ AUTHENTICATOR_PERMANENT_LOCKED);
assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)).isEqualTo(
- AUTHENTICATOR_LOCKED);
+ AUTHENTICATOR_PERMANENT_LOCKED);
}
+ @Test
+ public void testLockoutAndAuth() {
+ mAuthResultCoordinator.lockedOutFor(
+ BiometricManager.Authenticators.BIOMETRIC_WEAK);
+ mAuthResultCoordinator.authenticatedFor(
+ BiometricManager.Authenticators.BIOMETRIC_STRONG);
+
+ final Map<Integer, Integer> authMap = mAuthResultCoordinator.getResult();
+
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_STRONG)
+ & AUTHENTICATOR_UNLOCKED).isEqualTo(
+ AUTHENTICATOR_UNLOCKED);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_WEAK)
+ & AUTHENTICATOR_UNLOCKED).isEqualTo(
+ AUTHENTICATOR_UNLOCKED);
+ assertThat(authMap.get(BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE)
+ & AUTHENTICATOR_UNLOCKED).isEqualTo(
+ AUTHENTICATOR_UNLOCKED);
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthSessionCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthSessionCoordinatorTest.java
index c3b9cb1..f26c7e6 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthSessionCoordinatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AuthSessionCoordinatorTest.java
@@ -154,7 +154,7 @@
LockoutTracker.LOCKOUT_NONE);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
- assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
+ assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
}
@@ -194,7 +194,7 @@
LockoutTracker.LOCKOUT_NONE);
assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
- assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
+ assertThat(mCoordinator.getLockoutStateFor(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/MultiBiometricLockoutStateTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/MultiBiometricLockoutStateTest.java
index 968844e4c..c28de55 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/MultiBiometricLockoutStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/MultiBiometricLockoutStateTest.java
@@ -49,7 +49,7 @@
private Clock mClock;
private static void unlockAllBiometrics(MultiBiometricLockoutState lockoutState, int userId) {
- lockoutState.setAuthenticatorTo(userId, BIOMETRIC_STRONG, true /* canAuthenticate */);
+ lockoutState.clearPermanentLockOut(userId, BIOMETRIC_STRONG);
assertThat(lockoutState.getLockoutState(userId, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(lockoutState.getLockoutState(userId, BIOMETRIC_WEAK)).isEqualTo(
@@ -59,7 +59,7 @@
}
private static void lockoutAllBiometrics(MultiBiometricLockoutState lockoutState, int userId) {
- lockoutState.setAuthenticatorTo(userId, BIOMETRIC_STRONG, false /* canAuthenticate */);
+ lockoutState.setPermanentLockOut(userId, BIOMETRIC_STRONG);
assertThat(lockoutState.getLockoutState(userId, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(lockoutState.getLockoutState(userId, BIOMETRIC_WEAK)).isEqualTo(
@@ -96,8 +96,7 @@
@Test
public void testConvenienceLockout() {
unlockAllBiometrics();
- mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_CONVENIENCE,
- false /* canAuthenticate */);
+ mLockoutState.setPermanentLockOut(PRIMARY_USER, BIOMETRIC_CONVENIENCE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
@@ -110,7 +109,7 @@
@Test
public void testWeakLockout() {
unlockAllBiometrics();
- mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_WEAK, false /* canAuthenticate */);
+ mLockoutState.setPermanentLockOut(PRIMARY_USER, BIOMETRIC_WEAK);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
@@ -123,8 +122,7 @@
@Test
public void testStrongLockout() {
lockoutAllBiometrics();
- mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_STRONG,
- false /* canAuthenticate */);
+ mLockoutState.setPermanentLockOut(PRIMARY_USER, BIOMETRIC_STRONG);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
@@ -137,8 +135,7 @@
@Test
public void testConvenienceUnlock() {
lockoutAllBiometrics();
- mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_CONVENIENCE,
- true /* canAuthenticate */);
+ mLockoutState.clearPermanentLockOut(PRIMARY_USER, BIOMETRIC_CONVENIENCE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
@@ -150,7 +147,7 @@
@Test
public void testWeakUnlock() {
lockoutAllBiometrics();
- mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_WEAK, true /* canAuthenticate */);
+ mLockoutState.clearPermanentLockOut(PRIMARY_USER, BIOMETRIC_WEAK);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
@@ -162,8 +159,7 @@
@Test
public void testStrongUnlock() {
lockoutAllBiometrics();
- mLockoutState.setAuthenticatorTo(PRIMARY_USER, BIOMETRIC_STRONG,
- true /* canAuthenticate */);
+ mLockoutState.clearPermanentLockOut(PRIMARY_USER, BIOMETRIC_STRONG);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
@@ -180,7 +176,7 @@
lockoutAllBiometrics(lockoutState, userOne);
lockoutAllBiometrics(lockoutState, userTwo);
- lockoutState.setAuthenticatorTo(userOne, BIOMETRIC_WEAK, true /* canAuthenticate */);
+ lockoutState.clearPermanentLockOut(userOne, BIOMETRIC_WEAK);
assertThat(lockoutState.getLockoutState(userOne, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_PERMANENT);
assertThat(lockoutState.getLockoutState(userOne, BIOMETRIC_WEAK)).isEqualTo(
@@ -205,8 +201,7 @@
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
- mLockoutState.increaseLockoutTime(PRIMARY_USER, BIOMETRIC_STRONG,
- System.currentTimeMillis() + 1);
+ mLockoutState.setTimedLockout(PRIMARY_USER, BIOMETRIC_STRONG);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_TIMED);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
@@ -225,8 +220,7 @@
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
- when(mClock.millis()).thenReturn(0L);
- mLockoutState.increaseLockoutTime(PRIMARY_USER, BIOMETRIC_STRONG, 1);
+ mLockoutState.setTimedLockout(PRIMARY_USER, BIOMETRIC_STRONG);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_TIMED);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
@@ -235,7 +229,7 @@
mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_CONVENIENCE)).isEqualTo(
LockoutTracker.LOCKOUT_TIMED);
- when(mClock.millis()).thenReturn(2L);
+ mLockoutState.clearTimedLockout(PRIMARY_USER, BIOMETRIC_STRONG);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_STRONG)).isEqualTo(
LockoutTracker.LOCKOUT_NONE);
assertThat(mLockoutState.getLockoutState(PRIMARY_USER, BIOMETRIC_WEAK)).isEqualTo(
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
index 1f29bec..9c9d3f8 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
@@ -19,6 +19,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
@@ -109,7 +111,8 @@
mUserSwitchCallback);
mHalCallback = new Sensor.HalSessionCallback(mContext, new Handler(mLooper.getLooper()),
TAG, mScheduler, SENSOR_ID,
- USER_ID, mLockoutCache, mLockoutResetDispatcher, mHalSessionCallback);
+ USER_ID, mLockoutCache, mLockoutResetDispatcher, mAuthSessionCoordinator,
+ mHalSessionCallback);
final SensorProps sensor1 = new SensorProps();
sensor1.commonProps = new CommonProps();
@@ -164,5 +167,6 @@
private void verifyNotLocked() {
assertEquals(LockoutTracker.LOCKOUT_NONE, mLockoutCache.getLockoutModeForUser(USER_ID));
verify(mLockoutResetDispatcher).notifyLockoutResetCallbacks(eq(SENSOR_ID));
+ verify(mAuthSessionCoordinator).resetLockoutFor(eq(USER_ID), anyInt(), anyLong());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
index 7ae4e17..0c13466 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
@@ -18,6 +18,8 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
@@ -97,7 +99,8 @@
mUserSwitchCallback);
mHalCallback = new Sensor.HalSessionCallback(mContext, new Handler(mLooper.getLooper()),
TAG, mScheduler, SENSOR_ID,
- USER_ID, mLockoutCache, mLockoutResetDispatcher, mHalSessionCallback);
+ USER_ID, mLockoutCache, mLockoutResetDispatcher, mAuthSessionCoordinator,
+ mHalSessionCallback);
}
@Test
@@ -130,5 +133,6 @@
private void verifyNotLocked() {
assertEquals(LockoutTracker.LOCKOUT_NONE, mLockoutCache.getLockoutModeForUser(USER_ID));
verify(mLockoutResetDispatcher).notifyLockoutResetCallbacks(eq(SENSOR_ID));
+ verify(mAuthSessionCoordinator).resetLockoutFor(eq(USER_ID), anyInt(), anyLong());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java
index e396263..728606f 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java
@@ -17,8 +17,13 @@
package com.android.server.devicestate;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -41,6 +46,8 @@
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
+import java.util.Locale;
+
/**
* Unit tests for {@link DeviceStateNotificationController}.
* <p/>
@@ -77,6 +84,8 @@
Notification.class);
private final NotificationManager mNotificationManager = mock(NotificationManager.class);
+ private DeviceStateNotificationController.NotificationInfoProvider mNotificationInfoProvider;
+
@Before
public void setup() throws Exception {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
@@ -97,6 +106,11 @@
THERMAL_TITLE_2, THERMAL_CONTENT_2,
POWER_SAVE_TITLE_2, POWER_SAVE_CONTENT_2));
+ mNotificationInfoProvider =
+ new DeviceStateNotificationController.NotificationInfoProvider(context);
+ mNotificationInfoProvider = spy(mNotificationInfoProvider);
+ doReturn(notificationInfos).when(mNotificationInfoProvider).loadNotificationInfos();
+
when(packageManager.getNameForUid(VALID_APP_UID)).thenReturn(VALID_APP_NAME);
when(packageManager.getNameForUid(INVALID_APP_UID)).thenReturn(INVALID_APP_NAME);
when(packageManager.getApplicationInfo(eq(VALID_APP_NAME), ArgumentMatchers.any()))
@@ -106,7 +120,7 @@
when(applicationInfo.loadLabel(eq(packageManager))).thenReturn(VALID_APP_LABEL);
mController = new DeviceStateNotificationController(
- context, handler, cancelStateRunnable, notificationInfos,
+ context, handler, cancelStateRunnable, mNotificationInfoProvider,
packageManager, mNotificationManager);
}
@@ -223,4 +237,26 @@
eq(DeviceStateNotificationController.NOTIFICATION_ID),
mNotificationCaptor.capture());
}
+
+ @Test
+ public void test_notificationInfoProvider() {
+ assertNull(mNotificationInfoProvider.getCachedLocale());
+
+ mNotificationInfoProvider.getNotificationInfos(Locale.ENGLISH);
+ verify(mNotificationInfoProvider).refreshNotificationInfos(eq(Locale.ENGLISH));
+ assertEquals(Locale.ENGLISH, mNotificationInfoProvider.getCachedLocale());
+ clearInvocations(mNotificationInfoProvider);
+
+ // If the same locale is used again, the provider uses the cached value, so it won't refresh
+ mNotificationInfoProvider.getNotificationInfos(Locale.ENGLISH);
+ verify(mNotificationInfoProvider, never()).refreshNotificationInfos(eq(Locale.ENGLISH));
+ assertEquals(Locale.ENGLISH, mNotificationInfoProvider.getCachedLocale());
+ clearInvocations(mNotificationInfoProvider);
+
+ // If a different locale is used, the provider refreshes.
+ mNotificationInfoProvider.getNotificationInfos(Locale.ITALY);
+ verify(mNotificationInfoProvider).refreshNotificationInfos(eq(Locale.ITALY));
+ assertEquals(Locale.ITALY, mNotificationInfoProvider.getCachedLocale());
+ clearInvocations(mNotificationInfoProvider);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index ad63da5..e960e99 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -16,9 +16,6 @@
package com.android.server.locksettings;
-import static android.app.admin.DevicePolicyManager.DEPRECATE_USERMANAGERINTERNAL_DEVICEPOLICY_FLAG;
-import static android.provider.DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER;
-
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -50,7 +47,6 @@
import android.os.UserManager;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
-import android.provider.DeviceConfig;
import android.provider.Settings;
import android.security.KeyStore;
@@ -235,9 +231,6 @@
// Adding a fake Device Owner app which will enable escrow token support in LSS.
when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(
new ComponentName("com.dummy.package", ".FakeDeviceOwner"));
- // TODO(b/258213147): Remove
- DeviceConfig.setProperty(NAMESPACE_DEVICE_POLICY_MANAGER,
- DEPRECATE_USERMANAGERINTERNAL_DEVICEPOLICY_FLAG, "true", /* makeDefault= */ false);
when(mUserManagerInternal.isDeviceManaged()).thenReturn(true);
when(mDeviceStateCache.isUserOrganizationManaged(anyInt())).thenReturn(true);
when(mDeviceStateCache.isDeviceProvisioned()).thenReturn(true);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
index 3f3b8d7..36dc6c5 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
@@ -87,7 +87,10 @@
PersistentDataBlockManagerInternal getPersistentDataBlockManager() {
return mPersistentDataBlockManager;
}
-
+ @Override
+ public boolean isAutoPinConfirmSettingEnabled(int userId) {
+ return true;
+ }
private File remapToStorageDir(File origPath) {
File mappedPath = new File(mStorageDir, origPath.toString());
mappedPath.getParentFile().mkdirs();
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
index e8ef398..a48d2cc 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
@@ -113,6 +113,11 @@
}
@Override
+ public boolean isAutoPinConfirmationFeatureAvailable() {
+ return true;
+ }
+
+ @Override
protected IWeaver getWeaverHidlService() throws RemoteException {
return mWeaverService;
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index bdc5be6..bfb6b0f1 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -607,6 +607,24 @@
}
@Test
+ public void testStorePinLengthOnDisk() {
+ int userId = 1;
+ LockscreenCredential lockscreenCredentialPin = LockscreenCredential.createPin("123456");
+ MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage,
+ mGateKeeperService, mUserManager, mPasswordSlotManager);
+ SyntheticPassword sp = manager.newSyntheticPassword(userId);
+ long protectorId = manager.createLskfBasedProtector(mGateKeeperService,
+ lockscreenCredentialPin, sp,
+ userId);
+ PasswordMetrics passwordMetrics =
+ PasswordMetrics.computeForCredential(lockscreenCredentialPin);
+ boolean result = manager.refreshPinLengthOnDisk(passwordMetrics, protectorId, userId);
+
+ assertEquals(manager.getPinLength(protectorId, userId), lockscreenCredentialPin.size());
+ assertTrue(result);
+ }
+
+ @Test
public void testPasswordDataV2VersionCredentialTypePin_deserialize() {
// Test that we can deserialize existing PasswordData and don't inadvertently change the
// wire format.
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
index d50aca9..2efd9fc 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -618,13 +618,19 @@
}
@Test
- public void shouldCancelVibrationOnScreenOff_withUidZero_returnsFalseForTouchAndHardware() {
+ public void shouldCancelVibrationOnScreenOff_withUidZero_returnsFalseForUsagesInAllowlist() {
long vibrateStartTime = 100;
mockGoToSleep(vibrateStartTime + 10, PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
+ Set<Integer> expectedAllowedVibrations = new HashSet<>(Arrays.asList(
+ USAGE_TOUCH,
+ USAGE_ACCESSIBILITY,
+ USAGE_PHYSICAL_EMULATION,
+ USAGE_HARDWARE_FEEDBACK
+ ));
+
for (int usage : ALL_USAGES) {
- if (usage == USAGE_TOUCH || usage == USAGE_HARDWARE_FEEDBACK
- || usage == USAGE_PHYSICAL_EMULATION) {
+ if (expectedAllowedVibrations.contains(usage)) {
assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
createCallerInfo(/* uid= */ 0, "", usage), vibrateStartTime));
} else {
@@ -635,13 +641,19 @@
}
@Test
- public void shouldCancelVibrationOnScreenOff_withSystemUid_returnsFalseForTouchAndHardware() {
+ public void shouldCancelVibrationOnScreenOff_withSystemUid__returnsFalseForUsagesInAllowlist() {
long vibrateStartTime = 100;
mockGoToSleep(vibrateStartTime + 10, PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD);
+ Set<Integer> expectedAllowedVibrations = new HashSet<>(Arrays.asList(
+ USAGE_TOUCH,
+ USAGE_ACCESSIBILITY,
+ USAGE_PHYSICAL_EMULATION,
+ USAGE_HARDWARE_FEEDBACK
+ ));
+
for (int usage : ALL_USAGES) {
- if (usage == USAGE_TOUCH || usage == USAGE_HARDWARE_FEEDBACK
- || usage == USAGE_PHYSICAL_EMULATION) {
+ if (expectedAllowedVibrations.contains(usage)) {
assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
createCallerInfo(Process.SYSTEM_UID, "", usage), vibrateStartTime));
} else {
@@ -652,13 +664,19 @@
}
@Test
- public void shouldCancelVibrationOnScreenOff_withSysUiPkg_returnsFalseForTouchAndHardware() {
+ public void shouldCancelVibrationOnScreenOff_withSysUiPkg_returnsFalseForUsagesInAllowlist() {
long vibrateStartTime = 100;
mockGoToSleep(vibrateStartTime + 10, PowerManager.GO_TO_SLEEP_REASON_HDMI);
+ Set<Integer> expectedAllowedVibrations = new HashSet<>(Arrays.asList(
+ USAGE_TOUCH,
+ USAGE_ACCESSIBILITY,
+ USAGE_PHYSICAL_EMULATION,
+ USAGE_HARDWARE_FEEDBACK
+ ));
+
for (int usage : ALL_USAGES) {
- if (usage == USAGE_TOUCH || usage == USAGE_HARDWARE_FEEDBACK
- || usage == USAGE_PHYSICAL_EMULATION) {
+ if (expectedAllowedVibrations.contains(usage)) {
assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
createCallerInfo(UID, SYSUI_PACKAGE_NAME, usage), vibrateStartTime));
} else {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index 7d16fb2..4890f3e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -44,11 +44,13 @@
import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.admin.DevicePolicyManagerInternal;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
@@ -445,12 +447,15 @@
}
@Test
- public void testSandboxServiceInterceptionHappensToSandboxedActivityAction()
- throws InterruptedException {
-
+ public void testSandboxServiceInterceptionHappensToIntentWithSandboxActivityAction() {
ActivityInterceptorCallback spyCallback = Mockito.spy(info -> null);
mActivityInterceptorCallbacks.put(MAINLINE_SDK_SANDBOX_ORDER_ID, spyCallback);
+ PackageManager packageManagerMock = mock(PackageManager.class);
+ String sandboxPackageNameMock = "com.sandbox.mock";
+ when(mContext.getPackageManager()).thenReturn(packageManagerMock);
+ when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock);
+
Intent intent = new Intent().setAction(ACTION_START_SANDBOXED_ACTIVITY);
mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
@@ -459,13 +464,68 @@
}
@Test
- public void testSandboxServiceInterceptionNotCalledForNotSandboxedActivityAction() {
+ public void testSandboxServiceInterceptionHappensToIntentWithSandboxPackage() {
ActivityInterceptorCallback spyCallback = Mockito.spy(info -> null);
mActivityInterceptorCallbacks.put(MAINLINE_SDK_SANDBOX_ORDER_ID, spyCallback);
+ PackageManager packageManagerMock = mock(PackageManager.class);
+ String sandboxPackageNameMock = "com.sandbox.mock";
+ when(mContext.getPackageManager()).thenReturn(packageManagerMock);
+ when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock);
+
+ Intent intent = new Intent().setPackage(sandboxPackageNameMock);
+ mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+
+ verify(spyCallback, times(1)).onInterceptActivityLaunch(
+ any(ActivityInterceptorCallback.ActivityInterceptorInfo.class));
+ }
+
+ @Test
+ public void testSandboxServiceInterceptionHappensToIntentWithComponentNameWithSandboxPackage() {
+ ActivityInterceptorCallback spyCallback = Mockito.spy(info -> null);
+ mActivityInterceptorCallbacks.put(MAINLINE_SDK_SANDBOX_ORDER_ID, spyCallback);
+
+ PackageManager packageManagerMock = mock(PackageManager.class);
+ String sandboxPackageNameMock = "com.sandbox.mock";
+ when(mContext.getPackageManager()).thenReturn(packageManagerMock);
+ when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock);
+
+ Intent intent = new Intent().setComponent(new ComponentName(sandboxPackageNameMock, ""));
+ mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+
+ verify(spyCallback, times(1)).onInterceptActivityLaunch(
+ any(ActivityInterceptorCallback.ActivityInterceptorInfo.class));
+ }
+
+ @Test
+ public void testSandboxServiceInterceptionNotCalledWhenIntentNotRelatedToSandbox() {
+ ActivityInterceptorCallback spyCallback = Mockito.spy(info -> null);
+ mActivityInterceptorCallbacks.put(MAINLINE_SDK_SANDBOX_ORDER_ID, spyCallback);
+
+ PackageManager packageManagerMock = mock(PackageManager.class);
+ String sandboxPackageNameMock = "com.sandbox.mock";
+ when(mContext.getPackageManager()).thenReturn(packageManagerMock);
+ when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock);
+
+ // Intent: null
+ mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null);
+
+ // Action: null, Package: null, ComponentName: null
Intent intent = new Intent();
mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+ // Wrong Action
+ intent = new Intent().setAction(Intent.ACTION_VIEW);
+ mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+
+ // Wrong Package
+ intent = new Intent().setPackage("Random");
+ mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+
+ // Wrong ComponentName's package
+ intent = new Intent().setComponent(new ComponentName("Random", ""));
+ mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+
verify(spyCallback, never()).onInterceptActivityLaunch(
any(ActivityInterceptorCallback.ActivityInterceptorInfo.class));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
index 2686a24..d2f0385 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
@@ -112,13 +112,6 @@
}
@Test
- public void testRegisterOrganizer_alreadyRegisteredFeature() {
- registerMockOrganizer(FEATURE_VENDOR_FIRST);
- assertThrows(IllegalStateException.class,
- () -> registerMockOrganizer(FEATURE_VENDOR_FIRST));
- }
-
- @Test
public void testRegisterOrganizer_ignoreUntrustedDisplay() throws RemoteException {
doReturn(false).when(mDisplayContent).isTrusted();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index 10540dc..1ad04a2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -619,19 +619,6 @@
}
@Test
- public void testRegisterSameFeatureOrganizer_expectThrowsException() {
- final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class);
- final IBinder binder = mock(IBinder.class);
- doReturn(true).when(binder).isBinderAlive();
- doReturn(binder).when(mockDisplayAreaOrganizer).asBinder();
- final DisplayAreaOrganizerController controller =
- mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController;
- controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST);
- assertThrows(IllegalStateException.class,
- () -> controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST));
- }
-
- @Test
public void testRegisterUnregisterOrganizer() {
final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class);
doReturn(mock(IBinder.class)).when(mockDisplayAreaOrganizer).asBinder();
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index 5e513f1..3934b02 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -94,6 +94,7 @@
mProvider.setWindowContainer(statusBar,
(displayFrames, windowState, rect) -> {
rect.set(10, 10, 20, 20);
+ return 0;
}, null);
mProvider.updateSourceFrame(statusBar.getFrame());
mProvider.onPostLayout();
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index ff2944a..d1d83f6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -52,7 +52,7 @@
import androidx.test.filters.SmallTest;
-import com.android.internal.util.function.TriConsumer;
+import com.android.internal.util.function.TriFunction;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -289,10 +289,12 @@
InsetsSourceProvider statusBarProvider =
getController().getOrCreateSourceProvider(ID_STATUS_BAR, statusBars());
- final SparseArray<TriConsumer<DisplayFrames, WindowContainer, Rect>> imeOverrideProviders =
- new SparseArray<>();
- imeOverrideProviders.put(TYPE_INPUT_METHOD, ((displayFrames, windowState, rect) ->
- rect.set(0, 1, 2, 3)));
+ final SparseArray<TriFunction<DisplayFrames, WindowContainer, Rect, Integer>>
+ imeOverrideProviders = new SparseArray<>();
+ imeOverrideProviders.put(TYPE_INPUT_METHOD, ((displayFrames, windowState, rect) -> {
+ rect.set(0, 1, 2, 3);
+ return 0;
+ }));
statusBarProvider.setWindowContainer(statusBar, null, imeOverrideProviders);
getController().getOrCreateSourceProvider(ID_IME, ime())
.setWindowContainer(ime, null, null);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index fdb3502..766e74c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -43,6 +43,8 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
+import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -969,6 +971,33 @@
assertFalse(sameTokenWindow.needsRelativeLayeringToIme());
}
+ @UseTestDisplay(addWindows = {W_ACTIVITY, W_INPUT_METHOD})
+ @Test
+ public void testNeedsRelativeLayeringToIme_systemDialog() {
+ WindowState systemDialogWindow = createWindow(null, TYPE_SECURE_SYSTEM_OVERLAY,
+ mDisplayContent,
+ "SystemDialog", true);
+ mDisplayContent.setImeLayeringTarget(mAppWindow);
+ mAppWindow.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ makeWindowVisible(mImeWindow);
+ systemDialogWindow.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
+ assertTrue(systemDialogWindow.needsRelativeLayeringToIme());
+ }
+
+ @UseTestDisplay(addWindows = {W_INPUT_METHOD})
+ @Test
+ public void testNeedsRelativeLayeringToIme_notificationShadeShouldNotHideSystemDialog() {
+ WindowState systemDialogWindow = createWindow(null, TYPE_SECURE_SYSTEM_OVERLAY,
+ mDisplayContent,
+ "SystemDialog", true);
+ mDisplayContent.setImeLayeringTarget(systemDialogWindow);
+ makeWindowVisible(mImeWindow);
+ WindowState notificationShade = createWindow(null, TYPE_NOTIFICATION_SHADE,
+ mDisplayContent, "NotificationShade", true);
+ notificationShade.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
+ assertFalse(notificationShade.needsRelativeLayeringToIme());
+ }
+
@Test
public void testSetFreezeInsetsState() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 74ba45c..3ec6f42 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -22,6 +22,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
@@ -31,6 +32,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
@@ -553,6 +555,30 @@
}
@Test
+ public void testSystemDialogWindow_expectHigherThanIme_inMultiWindow() {
+ // Simulate the app window is in multi windowing mode and being IME target
+ mAppWindow.getConfiguration().windowConfiguration.setWindowingMode(
+ WINDOWING_MODE_MULTI_WINDOW);
+ mDisplayContent.setImeLayeringTarget(mAppWindow);
+ mDisplayContent.setImeInputTarget(mAppWindow);
+ makeWindowVisible(mImeWindow);
+
+ // Create a popupWindow
+ final WindowState systemDialogWindow = createWindow(null, TYPE_SECURE_SYSTEM_OVERLAY,
+ mDisplayContent, "SystemDialog", true);
+ systemDialogWindow.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
+ spyOn(systemDialogWindow);
+
+ mDisplayContent.assignChildLayers(mTransaction);
+
+ // Verify the surface layer of the popupWindow should higher than IME
+ verify(systemDialogWindow).needsRelativeLayeringToIme();
+ assertThat(systemDialogWindow.needsRelativeLayeringToIme()).isTrue();
+ assertZOrderGreaterThan(mTransaction, systemDialogWindow.getSurfaceControl(),
+ mDisplayContent.getImeContainer().getSurfaceControl());
+ }
+
+ @Test
public void testImeScreenshotLayer() {
final Task task = createTask(mDisplayContent);
final WindowState imeAppTarget = createAppWindow(task, TYPE_APPLICATION, "imeAppTarget");
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 1bbea89..790be8d 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -73,7 +73,6 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
-import android.os.Parcel;
import android.os.ParcelUuid;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -342,21 +341,6 @@
}
@Override
- public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
- throws RemoteException {
- try {
- return super.onTransact(code, data, reply, flags);
- } catch (RuntimeException e) {
- // The activity manager only throws security exceptions, so let's
- // log all others.
- if (!(e instanceof SecurityException)) {
- Slog.wtf(TAG, "SoundTriggerService Crash", e);
- }
- throw e;
- }
- }
-
- @Override
public int startRecognition(GenericSoundModel soundModel,
IRecognitionStatusCallback callback,
RecognitionConfig config, boolean runInBatterySaverMode) {
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/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/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
index 1b4d6ad..10ce5ea 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.ime
-import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.IwTest
import android.platform.test.annotations.Presubmit
import android.tools.common.datatypes.component.ComponentNameMatcher
@@ -80,7 +79,7 @@
flicker.navBarLayerPositionAtStartAndEnd()
}
- @FlakyTest
+ @Presubmit
@Test
fun navBarLayerPositionAtStartAndEndLandscapeOrSeascapeAtStart() {
Assume.assumeFalse(flicker.scenario.isTablet)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
index 3a8db45..3f87aef 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
@@ -15,7 +15,7 @@
*/
package com.android.server.wm.flicker.ime
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.common.Rotation
import android.tools.common.datatypes.component.ComponentNameMatcher
@@ -60,19 +60,19 @@
}
}
- @Postsubmit
+ @Presubmit
@Test
fun imeLayerVisibleStart() {
flicker.assertLayersStart { this.isVisible(ComponentNameMatcher.IME) }
}
- @Postsubmit
+ @Presubmit
@Test
fun imeLayerExistsEnd() {
flicker.assertLayersEnd { this.isVisible(ComponentNameMatcher.IME) }
}
- @Postsubmit
+ @Presubmit
@Test
fun imeLayerVisibleRegionKeepsTheSame() {
var imeLayerVisibleRegionBeforeTransition: RegionSubject? = null
@@ -85,7 +85,7 @@
}
}
- @Postsubmit
+ @Presubmit
@Test
fun appWindowWithLetterboxCoversExactlyOnScreen() {
val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
index 12c0874..b1a267a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
@@ -16,12 +16,9 @@
package com.android.server.wm.flicker.launch
-import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Postsubmit
-import android.platform.test.annotations.Presubmit
import android.platform.test.rule.SettingOverrideRule
import android.provider.Settings
-import android.tools.common.datatypes.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
@@ -68,12 +65,6 @@
}
/** {@inheritDoc} */
- @FlakyTest(bugId = 203538234)
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- /** {@inheritDoc} */
@Test @Ignore("Display is off at the start") override fun navBarLayerPositionAtStartAndEnd() {}
/** {@inheritDoc} */
@@ -89,6 +80,11 @@
/** {@inheritDoc} */
@Test
@Ignore("Display is off at the start")
+ override fun taskBarWindowIsAlwaysVisible() {}
+
+ /** {@inheritDoc} */
+ @Test
+ @Ignore("Display is off at the start")
override fun statusBarLayerIsVisibleAtStartAndEnd() =
super.statusBarLayerIsVisibleAtStartAndEnd()
@@ -97,14 +93,6 @@
@Ignore("Not applicable to this CUJ. Display starts locked and app is full screen at the end")
override fun navBarWindowIsVisibleAtStartAndEnd() = super.navBarWindowIsVisibleAtStartAndEnd()
- /**
- * Checks the position of the [ComponentNameMatcher.STATUS_BAR] at the start and end of the
- * transition
- */
- @Presubmit
- @Test
- override fun statusBarLayerPositionAtEnd() = super.statusBarLayerPositionAtEnd()
-
/** {@inheritDoc} */
@Test
@Ignore("Not applicable to this CUJ. Display starts locked and app is full screen at the end")
@@ -143,7 +131,7 @@
val disableUnseenNotifFilterRule =
SettingOverrideRule(
Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS,
- /* value= */ "0",
+ /* value = */ "0",
)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
index 222caed..e414325 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
@@ -97,6 +97,11 @@
/** {@inheritDoc} */
@Test
+ @Ignore("Not applicable to this CUJ. Display starts locked and app is full screen at the end")
+ override fun taskBarWindowIsAlwaysVisible() {}
+
+ /** {@inheritDoc} */
+ @Test
@Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
override fun statusBarLayerPositionAtStartAndEnd() {}
@@ -128,9 +133,6 @@
override fun navBarWindowIsAlwaysVisible() {}
/** {@inheritDoc} */
- @FlakyTest @Test override fun appWindowBecomesVisible() = super.appWindowBecomesVisible()
-
- /** {@inheritDoc} */
@FlakyTest(bugId = 246284526)
@Test
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
index 4a9507a..23cb1d4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
@@ -191,12 +191,6 @@
@Postsubmit
override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
- /** {@inheritDoc} */
- @Postsubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index 9ab6156..17f5638 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -17,7 +17,6 @@
package com.android.server.wm.flicker.launch
import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.common.NavBar
import android.tools.common.Rotation
@@ -70,7 +69,7 @@
* Checks that the [ComponentNameMatcher.NAV_BAR] layer starts invisible, becomes visible during
* unlocking animation and remains visible at the end
*/
- @FlakyTest(bugId = 227083463)
+ @Presubmit
@Test
fun navBarLayerVisibilityChanges() {
Assume.assumeFalse(flicker.scenario.isTablet)
@@ -155,8 +154,19 @@
@Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
override fun statusBarWindowIsAlwaysVisible() {}
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun appWindowBecomesFirstAndOnlyTopWindow() =
+ super.appWindowBecomesFirstAndOnlyTopWindow()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun appWindowBecomesVisible() = super.appWindowBecomesVisible()
+
/** Checks the [ComponentNameMatcher.NAV_BAR] is visible at the end of the transition */
- @Postsubmit
+ @Presubmit
@Test
fun navBarLayerIsVisibleAtEnd() {
Assume.assumeFalse(flicker.scenario.isTablet)
@@ -185,18 +195,11 @@
super.appLayerBecomesVisible()
}
- /** {@inheritDoc} */
- @FlakyTest @Test override fun entireScreenCovered() = super.entireScreenCovered()
-
- @FlakyTest(bugId = 218470989)
+ @Presubmit
@Test
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
- @FlakyTest(bugId = 227143265)
- @Test
- override fun appWindowBecomesTopWindow() = super.appWindowBecomesTopWindow()
-
@FlakyTest(bugId = 251217585)
@Test
override fun focusChanges() {
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 786bb32..18e49fe 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
@@ -24,11 +24,12 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
import android.view.KeyEvent
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.setRotation
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
import org.junit.FixMethodOrder
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -44,6 +45,7 @@
* Make sure no apps are running on the device
* Launch an app [testApp] and wait animation to complete
* ```
+ *
* Notes:
* ```
* 1. Some default assertions (e.g., nav bar, status bar and screen covered)
@@ -112,16 +114,16 @@
@Test
override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
- @Postsubmit
+ @Ignore("Status bar visibility depends on whether the permission dialog is displayed or not")
@Test
override fun statusBarLayerIsVisibleAtStartAndEnd() =
super.statusBarLayerIsVisibleAtStartAndEnd()
- @Postsubmit
+ @Ignore("Status bar visibility depends on whether the permission dialog is displayed or not")
@Test
override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
- @Postsubmit
+ @Ignore("Status bar visibility depends on whether the permission dialog is displayed or not")
@Test
override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java
index 0c7e452..9c70e6e 100644
--- a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java
+++ b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java
@@ -32,6 +32,7 @@
import android.app.Instrumentation;
import android.content.Intent;
+import android.content.res.Configuration;
import android.os.SystemClock;
import android.platform.test.annotations.RootPermissionTest;
import android.platform.test.rule.UnlockScreenRule;
@@ -69,8 +70,6 @@
new PressHomeBeforeTestRule();
@Rule(order = 4) public ScreenCaptureRule mScreenCaptureRule =
new ScreenCaptureRule("/sdcard/InputMethodStressTest");
-
- // TODO(b/240359838): add test case {@code Configuration.SCREENLAYOUT_SIZE_LARGE}.
@Parameterized.Parameters(
name = "windowFocusFlags={0}, softInputVisibility={1}, softInputAdjustment={2}")
public static List<Object[]> windowAndSoftInputFlagParameters() {
@@ -80,11 +79,14 @@
private final int mSoftInputFlags;
private final int mWindowFocusFlags;
private final Instrumentation mInstrumentation;
+ private final boolean mIsLargeScreen;
public AutoShowTest(int windowFocusFlags, int softInputVisibility, int softInputAdjustment) {
mSoftInputFlags = softInputVisibility | softInputAdjustment;
mWindowFocusFlags = windowFocusFlags;
mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mIsLargeScreen = mInstrumentation.getContext().getResources()
+ .getConfiguration().isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
}
/**
@@ -322,8 +324,7 @@
verifyClickBehavior(activity);
}
- public static void verifyAutoShowBehavior_forwardWithKeyboardOff(TestActivity activity) {
- // public: also used by ImeOpenCloseStressTest
+ private void verifyAutoShowBehavior_forwardWithKeyboardOff(TestActivity activity) {
if (hasUnfocusableWindowFlags(activity)) {
verifyImeAlwaysHiddenWithWindowFlagSet(activity);
return;
@@ -353,12 +354,12 @@
break;
}
case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED: {
- if (softInputAdjustment
- == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
+ if ((softInputAdjustment
+ == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) || mIsLargeScreen) {
// The current system behavior will choose to show IME automatically when
// navigating forward to an app that has no visibility state specified
// (i.e. SOFT_INPUT_STATE_UNSPECIFIED) with set SOFT_INPUT_ADJUST_RESIZE
- // flag.
+ // flag or running on a large screen device.
waitOnMainUntilImeIsShown(editText);
} else {
verifyImeIsAlwaysHidden(editText);
@@ -370,7 +371,7 @@
}
}
- private static void verifyAutoShowBehavior_forwardWithKeyboardOn(TestActivity activity) {
+ private void verifyAutoShowBehavior_forwardWithKeyboardOn(TestActivity activity) {
int windowFlags = activity.getWindow().getAttributes().flags;
int softInputMode = activity.getWindow().getAttributes().softInputMode;
int softInputVisibility = softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE;
@@ -414,12 +415,12 @@
break;
}
case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED: {
- if (softInputAdjustment
- == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
+ if ((softInputAdjustment
+ == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) || mIsLargeScreen) {
// The current system behavior will choose to show IME automatically when
- // navigating
- // forward to an app that has no visibility state specified (i.e.
- // SOFT_INPUT_STATE_UNSPECIFIED) with set SOFT_INPUT_ADJUST_RESIZE flag.
+ // navigating forward to an app that has no visibility state specified (i.e.
+ // SOFT_INPUT_STATE_UNSPECIFIED) with set SOFT_INPUT_ADJUST_RESIZE flag or
+ // running on a large screen device.
waitOnMainUntilImeIsShown(editText);
} else {
verifyImeIsAlwaysHidden(editText);
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;