summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/IActivityManager.aidl37
-rw-r--r--core/java/android/app/IWallpaperManager.aidl8
-rw-r--r--core/java/android/app/WallpaperManager.java257
-rw-r--r--core/java/android/content/pm/PackageInstaller.java6
-rw-r--r--core/java/android/provider/Settings.java16
-rw-r--r--core/java/android/view/autofill/AutofillClientController.java6
-rw-r--r--core/java/android/view/autofill/AutofillManager.java12
-rw-r--r--core/java/com/android/internal/util/LatencyTracker.java82
-rw-r--r--core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java8
-rw-r--r--core/tests/coretests/testdoubles/src/com/android/internal/util/FakeLatencyTracker.java179
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java10
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt2
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt2
-rw-r--r--packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml7
-rw-r--r--packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml1
-rw-r--r--packages/SystemUI/res/layout/mobile_signal_group.xml7
-rw-r--r--packages/SystemUI/res/values/dimens.xml1
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIApplication.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java57
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt574
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java7
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt7
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java62
-rw-r--r--services/core/java/com/android/server/am/UidObserverController.java137
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java8
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderClearSession.java3
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderCreateSession.java3
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderGetSession.java3
-rw-r--r--services/credentials/java/com/android/server/credentials/RemoteCredentialService.java133
-rw-r--r--services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java3
-rw-r--r--services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java62
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java4
44 files changed, 1114 insertions, 758 deletions
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 99ef315676c4..e9fbf6b178fb 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -102,6 +102,43 @@ interface IActivityManager {
void registerUidObserver(in IUidObserver observer, int which, int cutpoint,
String callingPackage);
void unregisterUidObserver(in IUidObserver observer);
+
+ /**
+ * Registers a UidObserver with a uid filter.
+ *
+ * @param observer The UidObserver implementation to register.
+ * @param which A bitmask of events to observe. See ActivityManager.UID_OBSERVER_*.
+ * @param cutpoint The cutpoint for onUidStateChanged events. When the state crosses this
+ * threshold in either direction, onUidStateChanged will be called.
+ * @param callingPackage The name of the calling package.
+ * @param uids A list of uids to watch. If all uids are to be watched, use
+ * registerUidObserver instead.
+ * @throws RemoteException
+ * @return Returns A binder token identifying the UidObserver registration.
+ */
+ IBinder registerUidObserverForUids(in IUidObserver observer, int which, int cutpoint,
+ String callingPackage, in int[] uids);
+
+ /**
+ * Adds a uid to the list of uids that a UidObserver will receive updates about.
+ *
+ * @param observerToken The binder token identifying the UidObserver registration.
+ * @param callingPackage The name of the calling package.
+ * @param uid The uid to watch.
+ * @throws RemoteException
+ */
+ void addUidToObserver(in IBinder observerToken, String callingPackage, int uid);
+
+ /**
+ * Removes a uid from the list of uids that a UidObserver will receive updates about.
+ *
+ * @param observerToken The binder token identifying the UidObserver registration.
+ * @param callingPackage The name of the calling package.
+ * @param uid The uid to stop watching.
+ * @throws RemoteException
+ */
+ void removeUidFromObserver(in IBinder observerToken, String callingPackage, int uid);
+
boolean isUidActive(int uid, String callingPackage);
@JavaPassthrough(annotation=
"@android.annotation.RequiresPermission(allOf = {android.Manifest.permission.PACKAGE_USAGE_STATS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional = true)")
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 2b1558937d21..4d308d90ce2d 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -259,6 +259,14 @@ interface IWallpaperManager {
boolean lockScreenWallpaperExists();
/**
+ * Return true if there is a static wallpaper on the specified screen. With which=FLAG_LOCK,
+ * always return false if the lock screen doesn't run its own wallpaper engine.
+ *
+ * @hide
+ */
+ boolean isStaticWallpaper(int which);
+
+ /**
* Temporary method for project b/197814683.
* Return true if the lockscreen wallpaper always uses a WallpaperService, not a static image.
* @hide
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 70c42d8f3b8a..c0106ab0bc11 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -658,15 +658,8 @@ public class WallpaperManager {
return currentWallpaper;
}
}
- if (returnDefault) {
- Bitmap defaultWallpaper = mDefaultWallpaper;
- if (defaultWallpaper == null || defaultWallpaper.isRecycled()) {
- defaultWallpaper = getDefaultWallpaper(context, which);
- synchronized (this) {
- mDefaultWallpaper = defaultWallpaper;
- }
- }
- return defaultWallpaper;
+ if (returnDefault || (which == FLAG_LOCK && isStaticWallpaper(FLAG_LOCK))) {
+ return getDefaultWallpaper(context, which);
}
return null;
}
@@ -705,7 +698,7 @@ public class WallpaperManager {
}
// If user wallpaper is unavailable, may be the default one instead.
if ((dimensions == null || dimensions.width() == 0 || dimensions.height() == 0)
- && returnDefault) {
+ && (returnDefault || (which == FLAG_LOCK && isStaticWallpaper(FLAG_LOCK)))) {
InputStream is = openDefaultWallpaper(context, which);
if (is != null) {
try {
@@ -769,18 +762,39 @@ public class WallpaperManager {
}
private Bitmap getDefaultWallpaper(Context context, @SetWallpaperFlags int which) {
- InputStream is = openDefaultWallpaper(context, which);
- if (is != null) {
- try {
- BitmapFactory.Options options = new BitmapFactory.Options();
- return BitmapFactory.decodeStream(is, null, options);
- } catch (OutOfMemoryError e) {
+ Bitmap defaultWallpaper = mDefaultWallpaper;
+ if (defaultWallpaper == null || defaultWallpaper.isRecycled()) {
+ defaultWallpaper = null;
+ try (InputStream is = openDefaultWallpaper(context, which)) {
+ if (is != null) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ defaultWallpaper = BitmapFactory.decodeStream(is, null, options);
+ }
+ } catch (OutOfMemoryError | IOException e) {
Log.w(TAG, "Can't decode stream", e);
- } finally {
- IoUtils.closeQuietly(is);
}
}
- return null;
+ synchronized (this) {
+ mDefaultWallpaper = defaultWallpaper;
+ }
+ return defaultWallpaper;
+ }
+
+ /**
+ * Return true if there is a static wallpaper on the specified screen.
+ * With {@code which=}{@link #FLAG_LOCK}, always return false if the lockscreen doesn't run
+ * its own wallpaper engine.
+ */
+ private boolean isStaticWallpaper(@SetWallpaperFlags int which) {
+ if (mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ throw new RuntimeException(new DeadSystemException());
+ }
+ try {
+ return mService.isStaticWallpaper(which);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
}
@@ -882,21 +896,14 @@ public class WallpaperManager {
* <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
* can still access the real wallpaper on all versions. </li>
* </ul>
- * <br>
*
- * Retrieve the current system wallpaper; if
- * no wallpaper is set, the system built-in static wallpaper is returned.
- * This is returned as an
- * abstract Drawable that you can install in a View to display whatever
- * wallpaper the user has currently set.
* <p>
- * This method can return null if there is no system wallpaper available, if
- * wallpapers are not supported in the current user, or if the calling app is not
- * permitted to access the system wallpaper.
+ * Equivalent to {@link #getDrawable(int)} with {@code which=}{@link #FLAG_SYSTEM}.
+ * </p>
+ *
+ * @return A Drawable object for the requested wallpaper.
*
- * @return Returns a Drawable object that will draw the system wallpaper,
- * or {@code null} if no system wallpaper exists or if the calling application
- * is not able to access the wallpaper.
+ * @see #getDrawable(int)
*
* @throws SecurityException as described in the note
*/
@@ -919,23 +926,29 @@ public class WallpaperManager {
* <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
* can still access the real wallpaper on all versions. </li>
* </ul>
- * <br>
*
- * Retrieve the requested wallpaper; if
- * no wallpaper is set, the requested built-in static wallpaper is returned.
- * This is returned as an
- * abstract Drawable that you can install in a View to display whatever
- * wallpaper the user has currently set.
* <p>
- * This method can return null if the requested wallpaper is not available, if
- * wallpapers are not supported in the current user, or if the calling app is not
- * permitted to access the requested wallpaper.
+ * Retrieve the requested wallpaper for the specified wallpaper type if the wallpaper is not
+ * a live wallpaper. This method should not be used to display the user wallpaper on an app:
+ * {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WALLPAPER} should be used instead.
+ * </p>
+ * <p>
+ * When called with {@code which=}{@link #FLAG_SYSTEM},
+ * if there is a live wallpaper on home screen, the built-in default wallpaper is returned.
+ * </p>
+ * <p>
+ * When called with {@code which=}{@link #FLAG_LOCK}, if there is a live wallpaper
+ * on lock screen, or if the lock screen and home screen share the same wallpaper engine,
+ * {@code null} is returned.
+ * </p>
+ * <p>
+ * {@link #getWallpaperInfo(int)} can be used to determine whether there is a live wallpaper
+ * on a specified screen type.
+ * </p>
*
- * @param which The {@code FLAG_*} identifier of a valid wallpaper type. Throws
+ * @param which The {@code FLAG_*} identifier of a valid wallpaper type. Throws
* IllegalArgumentException if an invalid wallpaper is requested.
- * @return Returns a Drawable object that will draw the requested wallpaper,
- * or {@code null} if the requested wallpaper does not exist or if the calling application
- * is not able to access the wallpaper.
+ * @return A Drawable object for the requested wallpaper.
*
* @throws SecurityException as described in the note
*/
@@ -943,7 +956,8 @@ public class WallpaperManager {
@RequiresPermission(anyOf = {MANAGE_EXTERNAL_STORAGE, READ_WALLPAPER_INTERNAL})
public Drawable getDrawable(@SetWallpaperFlags int which) {
final ColorManagementProxy cmProxy = getColorManagementProxy();
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, which, cmProxy);
+ boolean returnDefault = which != FLAG_LOCK;
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, returnDefault, which, cmProxy);
if (bm != null) {
Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
dr.setDither(false);
@@ -1175,15 +1189,14 @@ public class WallpaperManager {
* <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
* can still access the real wallpaper on all versions. </li>
* </ul>
- * <br>
*
- * Retrieve the current system wallpaper; if there is no wallpaper set,
- * a null pointer is returned. This is returned as an
- * abstract Drawable that you can install in a View to display whatever
- * wallpaper the user has currently set.
+ * <p>
+ * Equivalent to {@link #getDrawable()}.
+ * </p>
+ *
+ * @return A Drawable object for the requested wallpaper.
*
- * @return Returns a Drawable object that will draw the wallpaper or a
- * null pointer if wallpaper is unset.
+ * @see #getDrawable()
*
* @throws SecurityException as described in the note
*/
@@ -1206,31 +1219,23 @@ public class WallpaperManager {
* <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
* can still access the real wallpaper on all versions. </li>
* </ul>
- * <br>
*
- * Retrieve the requested wallpaper; if there is no wallpaper set,
- * a null pointer is returned. This is returned as an
- * abstract Drawable that you can install in a View to display whatever
- * wallpaper the user has currently set.
+ * <p>
+ * Equivalent to {@link #getDrawable(int)}.
+ * </p>
*
- * @param which The {@code FLAG_*} identifier of a valid wallpaper type. Throws
+ * @param which The {@code FLAG_*} identifier of a valid wallpaper type. Throws
* IllegalArgumentException if an invalid wallpaper is requested.
- * @return Returns a Drawable object that will draw the wallpaper or a null pointer if
- * wallpaper is unset.
+ * @return A Drawable object for the requested wallpaper.
+ *
+ * @see #getDrawable(int)
*
* @throws SecurityException as described in the note
*/
@Nullable
@RequiresPermission(anyOf = {MANAGE_EXTERNAL_STORAGE, READ_WALLPAPER_INTERNAL})
public Drawable peekDrawable(@SetWallpaperFlags int which) {
- final ColorManagementProxy cmProxy = getColorManagementProxy();
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, which, cmProxy);
- if (bm != null) {
- Drawable dr = new BitmapDrawable(mContext.getResources(), bm);
- dr.setDither(false);
- return dr;
- }
- return null;
+ return getDrawable(which);
}
/**
@@ -1246,19 +1251,14 @@ public class WallpaperManager {
* <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
* can still access the real wallpaper on all versions. </li>
* </ul>
- * <br>
*
- * Like {@link #getDrawable()}, but the returned Drawable has a number
- * of limitations to reduce its overhead as much as possible. It will
- * never scale the wallpaper (only centering it if the requested bounds
- * do match the bitmap bounds, which should not be typical), doesn't
- * allow setting an alpha, color filter, or other attributes, etc. The
- * bounds of the returned drawable will be initialized to the same bounds
- * as the wallpaper, so normally you will not need to touch it. The
- * drawable also assumes that it will be used in a context running in
- * the same density as the screen (not in density compatibility mode).
+ * <p>
+ * Equivalent to {@link #getFastDrawable(int)} with {@code which=}{@link #FLAG_SYSTEM}.
+ * </p>
+ *
+ * @return A Drawable object for the requested wallpaper.
*
- * @return Returns a Drawable object that will draw the wallpaper.
+ * @see #getFastDrawable(int)
*
* @throws SecurityException as described in the note
*/
@@ -1295,7 +1295,8 @@ public class WallpaperManager {
*
* @param which The {@code FLAG_*} identifier of a valid wallpaper type. Throws
* IllegalArgumentException if an invalid wallpaper is requested.
- * @return Returns a Drawable object that will draw the wallpaper.
+ * @return An optimized Drawable object for the requested wallpaper, or {@code null}
+ * in some cases as specified in {@link #getDrawable(int)}.
*
* @throws SecurityException as described in the note
*/
@@ -1303,7 +1304,8 @@ public class WallpaperManager {
@RequiresPermission(anyOf = {MANAGE_EXTERNAL_STORAGE, READ_WALLPAPER_INTERNAL})
public Drawable getFastDrawable(@SetWallpaperFlags int which) {
final ColorManagementProxy cmProxy = getColorManagementProxy();
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, which, cmProxy);
+ boolean returnDefault = which != FLAG_LOCK;
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, returnDefault, which, cmProxy);
if (bm != null) {
return new FastBitmapDrawable(bm);
}
@@ -1323,13 +1325,14 @@ public class WallpaperManager {
* <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
* can still access the real wallpaper on all versions. </li>
* </ul>
- * <br>
*
- * Like {@link #getFastDrawable()}, but if there is no wallpaper set,
- * a null pointer is returned.
+ * <p>
+ * Equivalent to {@link #getFastDrawable()}.
+ * </p>
*
- * @return Returns an optimized Drawable object that will draw the
- * wallpaper or a null pointer if these is none.
+ * @return An optimized Drawable object for the requested wallpaper.
+ *
+ * @see #getFastDrawable()
*
* @throws SecurityException as described in the note
*/
@@ -1352,31 +1355,29 @@ public class WallpaperManager {
* <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
* can still access the real wallpaper on all versions. </li>
* </ul>
- * <br>
*
- * Like {@link #getFastDrawable()}, but if there is no wallpaper set,
- * a null pointer is returned.
+ * <p>
+ * Equivalent to {@link #getFastDrawable(int)}.
+ * </p>
*
* @param which The {@code FLAG_*} identifier of a valid wallpaper type. Throws
* IllegalArgumentException if an invalid wallpaper is requested.
- * @return Returns an optimized Drawable object that will draw the
- * wallpaper or a null pointer if these is none.
+ * @return An optimized Drawable object for the requested wallpaper.
*
* @throws SecurityException as described in the note
*/
@Nullable
@RequiresPermission(anyOf = {MANAGE_EXTERNAL_STORAGE, READ_WALLPAPER_INTERNAL})
public Drawable peekFastDrawable(@SetWallpaperFlags int which) {
- final ColorManagementProxy cmProxy = getColorManagementProxy();
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, which, cmProxy);
- if (bm != null) {
- return new FastBitmapDrawable(bm);
- }
- return null;
+ return getFastDrawable(which);
}
/**
- * Whether the wallpaper supports Wide Color Gamut or not.
+ * Whether the wallpaper supports Wide Color Gamut or not. This is only meant to be used by
+ * ImageWallpaper, and will always return false if the wallpaper for the specified screen
+ * is not an ImageWallpaper. This will also return false when called with {@link #FLAG_LOCK} if
+ * the lock and home screen share the same wallpaper engine.
+ *
* @param which The wallpaper whose image file is to be retrieved. Must be a single
* defined kind of wallpaper, either {@link #FLAG_SYSTEM} or {@link #FLAG_LOCK}.
* @return true when supported.
@@ -1422,7 +1423,7 @@ public class WallpaperManager {
}
/**
- * Like {@link #getDrawable()} but returns a Bitmap.
+ * Like {@link #getDrawable(int)} but returns a Bitmap.
*
* @param hardware Asks for a hardware backed bitmap.
* @param which Specifies home or lock screen
@@ -1445,7 +1446,7 @@ public class WallpaperManager {
}
/**
- * Like {@link #getDrawable()} but returns a Bitmap for the provided user.
+ * Like {@link #getDrawable(int)} but returns a Bitmap for the provided user.
*
* @param which Specifies home or lock screen
* @hide
@@ -1453,12 +1454,29 @@ public class WallpaperManager {
@TestApi
@Nullable
public Bitmap getBitmapAsUser(int userId, boolean hardware, @SetWallpaperFlags int which) {
+ boolean returnDefault = which != FLAG_LOCK;
+ return getBitmapAsUser(userId, hardware, which, returnDefault);
+ }
+
+ /**
+ * Overload of {@link #getBitmapAsUser(int, boolean, int)} with a returnDefault argument.
+ *
+ * @param returnDefault If true, return the default static wallpaper if no custom static
+ * wallpaper is set on the specified screen.
+ * If false, return {@code null} in that case.
+ * @hide
+ */
+ @Nullable
+ public Bitmap getBitmapAsUser(int userId, boolean hardware,
+ @SetWallpaperFlags int which, boolean returnDefault) {
final ColorManagementProxy cmProxy = getColorManagementProxy();
- return sGlobals.peekWallpaperBitmap(mContext, true, which, userId, hardware, cmProxy);
+ return sGlobals.peekWallpaperBitmap(mContext, returnDefault,
+ which, userId, hardware, cmProxy);
}
/**
* Peek the dimensions of system wallpaper of the user without decoding it.
+ * Equivalent to {@link #peekBitmapDimensions(int)} with {@code which=}{@link #FLAG_SYSTEM}.
*
* @return the dimensions of system wallpaper
* @hide
@@ -1472,16 +1490,45 @@ public class WallpaperManager {
/**
* Peek the dimensions of given wallpaper of the user without decoding it.
*
- * @param which Wallpaper type. Must be either {@link #FLAG_SYSTEM} or
- * {@link #FLAG_LOCK}.
- * @return the dimensions of system wallpaper
+ * <p>
+ * When called with {@code which=}{@link #FLAG_SYSTEM}, if there is a live wallpaper on
+ * home screen, the built-in default wallpaper dimensions are returned.
+ * </p>
+ * <p>
+ * When called with {@code which=}{@link #FLAG_LOCK}, if there is a live wallpaper
+ * on lock screen, or if the lock screen and home screen share the same wallpaper engine,
+ * {@code null} is returned.
+ * </p>
+ * <p>
+ * {@link #getWallpaperInfo(int)} can be used to determine whether there is a live wallpaper
+ * on a specified screen type.
+ * </p>
+ *
+ * @param which Wallpaper type. Must be either {@link #FLAG_SYSTEM} or {@link #FLAG_LOCK}.
+ * @return the dimensions of specified wallpaper
* @hide
*/
@TestApi
@Nullable
public Rect peekBitmapDimensions(@SetWallpaperFlags int which) {
+ boolean returnDefault = which != FLAG_LOCK;
+ return peekBitmapDimensions(which, returnDefault);
+ }
+
+ /**
+ * Overload of {@link #peekBitmapDimensions(int)} with a returnDefault argument.
+ *
+ * @param which Wallpaper type. Must be either {@link #FLAG_SYSTEM} or {@link #FLAG_LOCK}.
+ * @param returnDefault If true, always return the default static wallpaper dimensions
+ * if no custom static wallpaper is set on the specified screen.
+ * If false, always return {@code null} in that case.
+ * @return the dimensions of specified wallpaper
+ * @hide
+ */
+ @Nullable
+ public Rect peekBitmapDimensions(@SetWallpaperFlags int which, boolean returnDefault) {
checkExactlyOneWallpaperFlagSet(which);
- return sGlobals.peekWallpaperDimensions(mContext, true /* returnDefault */, which,
+ return sGlobals.peekWallpaperDimensions(mContext, returnDefault, which,
mContext.getUserId());
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 56f6f8206d30..d4e231b70c3e 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2565,9 +2565,9 @@ public class PackageInstaller {
* Sets the state of permissions for the package at installation.
* <p/>
* Granting any runtime permissions require the
- * {@link android.Manifest.permission#INSTALL_GRANT_RUNTIME_PERMISSIONS} permission to be
- * held by the caller. Revoking runtime permissions is not allowed, even during app update
- * sessions.
+ * {@link android.Manifest.permission#INSTALL_GRANT_RUNTIME_PERMISSIONS
+ * INSTALL_GRANT_RUNTIME_PERMISSIONS} permission to be held by the caller. Revoking runtime
+ * permissions is not allowed, even during app update sessions.
* <p/>
* Holders without the permission are allowed to change the following special permissions:
* <p/>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8cdb568b407c..73c29d4058cd 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3036,9 +3036,7 @@ public final class Settings {
public void destroy() {
try {
- // If this process is the system server process, mArray is the same object as
- // the memory int array kept inside SettingsProvider, so skipping the close()
- if (!Settings.isInSystemServer() && !mArray.isClosed()) {
+ if (!mArray.isClosed()) {
mArray.close();
}
} catch (IOException e) {
@@ -3218,8 +3216,9 @@ public final class Settings {
@UnsupportedAppUsage
public String getStringForUser(ContentResolver cr, String name, final int userHandle) {
final boolean isSelf = (userHandle == UserHandle.myUserId());
+ final boolean useCache = isSelf && !isInSystemServer();
boolean needsGenerationTracker = false;
- if (isSelf) {
+ if (useCache) {
synchronized (NameValueCache.this) {
final GenerationTracker generationTracker = mGenerationTrackers.get(name);
if (generationTracker != null) {
@@ -3365,9 +3364,12 @@ public final class Settings {
}
}
} else {
- if (LOCAL_LOGV) Log.i(TAG, "call-query of user " + userHandle
- + " by " + UserHandle.myUserId()
- + " so not updating cache");
+ if (DEBUG || LOCAL_LOGV) {
+ Log.i(TAG, "call-query of user " + userHandle
+ + " by " + UserHandle.myUserId()
+ + (isInSystemServer() ? " in system_server" : "")
+ + " so not updating cache");
+ }
}
return value;
}
diff --git a/core/java/android/view/autofill/AutofillClientController.java b/core/java/android/view/autofill/AutofillClientController.java
index 3a8e8027b88e..2f7adaa29fed 100644
--- a/core/java/android/view/autofill/AutofillClientController.java
+++ b/core/java/android/view/autofill/AutofillClientController.java
@@ -19,6 +19,7 @@ package android.view.autofill;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
+import android.app.ActivityOptions;
import android.app.Application;
import android.content.ComponentName;
import android.content.Intent;
@@ -486,8 +487,11 @@ public final class AutofillClientController implements AutofillManager.AutofillC
public void autofillClientAuthenticate(int authenticationId, IntentSender intent,
Intent fillInIntent, boolean authenticateInline) {
try {
+ ActivityOptions activityOptions = ActivityOptions.makeBasic()
+ .setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
mActivity.startIntentSenderForResult(intent, AUTO_FILL_AUTH_WHO_PREFIX,
- authenticationId, fillInIntent, 0, 0, null);
+ authenticationId, fillInIntent, 0, 0, activityOptions.toBundle());
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "authenticate() failed for intent:" + intent, e);
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index a6e9d4d2094f..5d121ad2957f 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1464,6 +1464,13 @@ public final class AutofillManager {
}
synchronized (mLock) {
+ if (mAllTrackedViews.contains(id)) {
+ // The id is tracked and will not trigger pre-fill request again.
+ return;
+ }
+
+ // Add the id as tracked to avoid triggering fill request again and again.
+ mAllTrackedViews.add(id);
if (mTrackedViews != null) {
// To support the fill dialog can show for the autofillable Views in
// different pages but in the same Activity. We need to reset the
@@ -4064,11 +4071,6 @@ public final class AutofillManager {
}
void checkViewState(AutofillId id) {
- if (mAllTrackedViews.contains(id)) {
- return;
- }
- // Add the id as tracked to avoid triggering fill request again and again.
- mAllTrackedViews.add(id);
if (mHasNewTrackedView) {
return;
}
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index c1445035ca33..f2776353fd1b 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -305,10 +305,17 @@ public class LatencyTracker {
private final SparseArray<ActionProperties> mActionPropertiesMap = new SparseArray<>();
@GuardedBy("mLock")
private boolean mEnabled;
+ private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
+ this::updateProperties;
// Wrapping this in a holder class achieves lazy loading behavior
private static final class SLatencyTrackerHolder {
- private static final LatencyTracker sLatencyTracker = new LatencyTracker();
+ private static final LatencyTracker sLatencyTracker;
+
+ static {
+ sLatencyTracker = new LatencyTracker();
+ sLatencyTracker.startListeningForLatencyTrackerConfigChanges();
+ }
}
public static LatencyTracker getInstance(Context context) {
@@ -319,31 +326,16 @@ public class LatencyTracker {
* Constructor for LatencyTracker
*
* <p>This constructor is only visible for test classes to inject their own consumer callbacks
+ *
+ * @param startListeningForPropertyChanges If set, constructor will register for device config
+ * property updates prior to returning. If not set,
+ * {@link #startListeningForLatencyTrackerConfigChanges} must be called
+ * to start listening.
*/
@RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
@VisibleForTesting
public LatencyTracker() {
mEnabled = DEFAULT_ENABLED;
-
- final Context context = ActivityThread.currentApplication();
- if (context != null
- && context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) == PERMISSION_GRANTED) {
- // Post initialization to the background in case we're running on the main thread.
- BackgroundThread.getHandler().post(() -> this.updateProperties(
- DeviceConfig.getProperties(NAMESPACE_LATENCY_TRACKER)));
- DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_LATENCY_TRACKER,
- BackgroundThread.getExecutor(), this::updateProperties);
- } else {
- if (DEBUG) {
- if (context == null) {
- Log.d(TAG, "No application for " + ActivityThread.currentActivityThread());
- } else {
- Log.d(TAG, "Initialized the LatencyTracker."
- + " (No READ_DEVICE_CONFIG permission to change configs)"
- + " enabled=" + mEnabled + ", package=" + context.getPackageName());
- }
- }
- }
}
private void updateProperties(DeviceConfig.Properties properties) {
@@ -366,6 +358,54 @@ public class LatencyTracker {
}
/**
+ * Test method to start listening to {@link DeviceConfig} properties changes.
+ *
+ * <p>During testing, a {@link LatencyTracker} it is desired to stop and start listening for
+ * config updates.
+ *
+ * <p>This is not used for production usages of this class outside of testing as we are
+ * using a single static object.
+ */
+ @VisibleForTesting
+ public void startListeningForLatencyTrackerConfigChanges() {
+ final Context context = ActivityThread.currentApplication();
+ if (context != null
+ && context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) == PERMISSION_GRANTED) {
+ // Post initialization to the background in case we're running on the main thread.
+ BackgroundThread.getHandler().post(() -> this.updateProperties(
+ DeviceConfig.getProperties(NAMESPACE_LATENCY_TRACKER)));
+ DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_LATENCY_TRACKER,
+ BackgroundThread.getExecutor(), mOnPropertiesChangedListener);
+ } else {
+ if (DEBUG) {
+ if (context == null) {
+ Log.d(TAG, "No application for " + ActivityThread.currentActivityThread());
+ } else {
+ synchronized (mLock) {
+ Log.d(TAG, "Initialized the LatencyTracker."
+ + " (No READ_DEVICE_CONFIG permission to change configs)"
+ + " enabled=" + mEnabled + ", package=" + context.getPackageName());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Test method to stop listening to {@link DeviceConfig} properties changes.
+ *
+ * <p>During testing, a {@link LatencyTracker} it is desired to stop and start listening for
+ * config updates.
+ *
+ * <p>This is not used for production usages of this class outside of testing as we are
+ * using a single static object.
+ */
+ @VisibleForTesting
+ public void stopListeningForLatencyTrackerConfigChanges() {
+ DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
+ }
+
+ /**
* A helper method to translate action type to name.
*
* @param atomsProtoAction the action type defined in AtomsProto.java
diff --git a/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java b/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java
index 645324d57ea9..584ad205a55d 100644
--- a/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/LatencyTrackerTest.java
@@ -28,12 +28,12 @@ import static com.google.common.truth.Truth.assertWithMessage;
import android.provider.DeviceConfig;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
import com.android.internal.util.LatencyTracker.ActionProperties;
import com.google.common.truth.Expect;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -48,7 +48,6 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
-@SmallTest
@RunWith(AndroidJUnit4.class)
public class LatencyTrackerTest {
private static final String ENUM_NAME_PREFIX = "UIACTION_LATENCY_REPORTED__ACTION__";
@@ -65,6 +64,11 @@ public class LatencyTrackerTest {
mLatencyTracker = FakeLatencyTracker.create();
}
+ @After
+ public void tearDown() {
+ mLatencyTracker.stopListeningForLatencyTrackerConfigChanges();
+ }
+
@Test
public void testCujsMapToEnumsCorrectly() {
List<Field> actions = getAllActionFields();
diff --git a/core/tests/coretests/testdoubles/src/com/android/internal/util/FakeLatencyTracker.java b/core/tests/coretests/testdoubles/src/com/android/internal/util/FakeLatencyTracker.java
index 61e976bee35e..76e69bf35aaf 100644
--- a/core/tests/coretests/testdoubles/src/com/android/internal/util/FakeLatencyTracker.java
+++ b/core/tests/coretests/testdoubles/src/com/android/internal/util/FakeLatencyTracker.java
@@ -25,8 +25,6 @@ import android.provider.DeviceConfig;
import android.util.Log;
import android.util.SparseArray;
-import androidx.annotation.Nullable;
-
import com.android.internal.annotations.GuardedBy;
import com.google.common.collect.ImmutableMap;
@@ -51,15 +49,17 @@ public final class FakeLatencyTracker extends LatencyTracker {
private final List<String> mPerfettoTraceNamesTriggered;
private final AtomicReference<SparseArray<ActionProperties>> mLastPropertiesUpdate =
new AtomicReference<>();
- @Nullable
- @GuardedBy("mLock")
- private Callable<Boolean> mShouldClosePropertiesUpdatedCallable = null;
+ private final AtomicReference<Callable<Boolean>> mShouldClosePropertiesUpdatedCallable =
+ new AtomicReference<>();
private final ConditionVariable mDeviceConfigPropertiesUpdated = new ConditionVariable();
public static FakeLatencyTracker create() throws Exception {
Log.i(TAG, "create");
disableForAllActions();
+ Log.i(TAG, "done disabling all actions");
FakeLatencyTracker fakeLatencyTracker = new FakeLatencyTracker();
+ Log.i(TAG, "done creating tracker object");
+ fakeLatencyTracker.startListeningForLatencyTrackerConfigChanges();
// always return the fake in the disabled state and let the client control the desired state
fakeLatencyTracker.waitForGlobalEnabledState(false);
fakeLatencyTracker.waitForAllPropertiesEnableState(false);
@@ -131,27 +131,25 @@ public final class FakeLatencyTracker extends LatencyTracker {
@Override
public void onDeviceConfigPropertiesUpdated(SparseArray<ActionProperties> actionProperties) {
Log.d(TAG, "onDeviceConfigPropertiesUpdated: " + actionProperties);
+
mLastPropertiesUpdate.set(actionProperties);
- synchronized (mLock) {
- if (mShouldClosePropertiesUpdatedCallable != null) {
- try {
- boolean shouldClosePropertiesUpdated =
- mShouldClosePropertiesUpdatedCallable.call();
- Log.i(TAG, "shouldClosePropertiesUpdatedCallable callable result="
- + shouldClosePropertiesUpdated);
- if (shouldClosePropertiesUpdated) {
- Log.i(TAG, "shouldClosePropertiesUpdatedCallable=true, opening condition");
- mShouldClosePropertiesUpdatedCallable = null;
- mDeviceConfigPropertiesUpdated.open();
- }
- } catch (Exception e) {
- Log.e(TAG, "exception when calling callable", e);
- throw new RuntimeException(e);
+ Callable<Boolean> shouldClosePropertiesUpdated =
+ mShouldClosePropertiesUpdatedCallable.get();
+ if (shouldClosePropertiesUpdated != null) {
+ try {
+ boolean result = shouldClosePropertiesUpdated.call();
+ Log.i(TAG, "shouldClosePropertiesUpdatedCallable callable result=" + result);
+ if (result) {
+ mShouldClosePropertiesUpdatedCallable.set(null);
+ mDeviceConfigPropertiesUpdated.open();
}
- } else {
- Log.i(TAG, "no conditional callable set, opening condition");
- mDeviceConfigPropertiesUpdated.open();
+ } catch (Exception e) {
+ Log.e(TAG, "exception when calling callable", e);
+ throw new RuntimeException(e);
}
+ } else {
+ Log.i(TAG, "no conditional callable set, opening condition");
+ mDeviceConfigPropertiesUpdated.open();
}
}
@@ -175,107 +173,82 @@ public final class FakeLatencyTracker extends LatencyTracker {
public void waitForAllPropertiesEnableState(boolean enabledState) throws Exception {
Log.i(TAG, "waitForAllPropertiesEnableState: enabledState=" + enabledState);
- synchronized (mLock) {
- Log.i(TAG, "closing condition");
- mDeviceConfigPropertiesUpdated.close();
- // Update the callable to only close the properties updated condition when all the
- // desired properties have been updated. The DeviceConfig callbacks may happen multiple
- // times so testing the resulting updates is required.
- mShouldClosePropertiesUpdatedCallable = () -> {
- Log.i(TAG, "verifying if last properties update has all properties enable="
- + enabledState);
- SparseArray<ActionProperties> newProperties = mLastPropertiesUpdate.get();
- if (newProperties != null) {
- for (int i = 0; i < newProperties.size(); i++) {
- if (newProperties.get(i).isEnabled() != enabledState) {
- return false;
- }
+ // Update the callable to only close the properties updated condition when all the
+ // desired properties have been updated. The DeviceConfig callbacks may happen multiple
+ // times so testing the resulting updates is required.
+ waitForPropertiesCondition(() -> {
+ Log.i(TAG, "verifying if last properties update has all properties enable="
+ + enabledState);
+ SparseArray<ActionProperties> newProperties = mLastPropertiesUpdate.get();
+ if (newProperties != null) {
+ for (int i = 0; i < newProperties.size(); i++) {
+ if (newProperties.get(i).isEnabled() != enabledState) {
+ return false;
}
}
- return true;
- };
- if (mShouldClosePropertiesUpdatedCallable.call()) {
- return;
}
- }
- Log.i(TAG, "waiting for condition");
- mDeviceConfigPropertiesUpdated.block();
+ return true;
+ });
}
public void waitForMatchingActionProperties(ActionProperties actionProperties)
throws Exception {
Log.i(TAG, "waitForMatchingActionProperties: actionProperties=" + actionProperties);
- synchronized (mLock) {
- Log.i(TAG, "closing condition");
- mDeviceConfigPropertiesUpdated.close();
- // Update the callable to only close the properties updated condition when all the
- // desired properties have been updated. The DeviceConfig callbacks may happen multiple
- // times so testing the resulting updates is required.
- mShouldClosePropertiesUpdatedCallable = () -> {
- Log.i(TAG, "verifying if last properties update contains matching property ="
- + actionProperties);
- SparseArray<ActionProperties> newProperties = mLastPropertiesUpdate.get();
- if (newProperties != null) {
- if (newProperties.size() > 0) {
- return newProperties.get(actionProperties.getAction()).equals(
- actionProperties);
- }
+ // Update the callable to only close the properties updated condition when all the
+ // desired properties have been updated. The DeviceConfig callbacks may happen multiple
+ // times so testing the resulting updates is required.
+ waitForPropertiesCondition(() -> {
+ Log.i(TAG, "verifying if last properties update contains matching property ="
+ + actionProperties);
+ SparseArray<ActionProperties> newProperties = mLastPropertiesUpdate.get();
+ if (newProperties != null) {
+ if (newProperties.size() > 0) {
+ return newProperties.get(actionProperties.getAction()).equals(
+ actionProperties);
}
- return false;
- };
- if (mShouldClosePropertiesUpdatedCallable.call()) {
- return;
}
- }
- Log.i(TAG, "waiting for condition");
- mDeviceConfigPropertiesUpdated.block();
+ return false;
+ });
}
public void waitForActionEnabledState(int action, boolean enabledState) throws Exception {
Log.i(TAG, "waitForActionEnabledState:"
+ " action=" + action + ", enabledState=" + enabledState);
- synchronized (mLock) {
- Log.i(TAG, "closing condition");
- mDeviceConfigPropertiesUpdated.close();
- // Update the callable to only close the properties updated condition when all the
- // desired properties have been updated. The DeviceConfig callbacks may happen multiple
- // times so testing the resulting updates is required.
- mShouldClosePropertiesUpdatedCallable = () -> {
- Log.i(TAG, "verifying if last properties update contains action=" + action
- + ", enabledState=" + enabledState);
- SparseArray<ActionProperties> newProperties = mLastPropertiesUpdate.get();
- if (newProperties != null) {
- if (newProperties.size() > 0) {
- return newProperties.get(action).isEnabled() == enabledState;
- }
+ // Update the callable to only close the properties updated condition when all the
+ // desired properties have been updated. The DeviceConfig callbacks may happen multiple
+ // times so testing the resulting updates is required.
+ waitForPropertiesCondition(() -> {
+ Log.i(TAG, "verifying if last properties update contains action=" + action
+ + ", enabledState=" + enabledState);
+ SparseArray<ActionProperties> newProperties = mLastPropertiesUpdate.get();
+ if (newProperties != null) {
+ if (newProperties.size() > 0) {
+ return newProperties.get(action).isEnabled() == enabledState;
}
- return false;
- };
- if (mShouldClosePropertiesUpdatedCallable.call()) {
- return;
}
- }
- Log.i(TAG, "waiting for condition");
- mDeviceConfigPropertiesUpdated.block();
+ return false;
+ });
}
public void waitForGlobalEnabledState(boolean enabledState) throws Exception {
Log.i(TAG, "waitForGlobalEnabledState: enabledState=" + enabledState);
- synchronized (mLock) {
- Log.i(TAG, "closing condition");
- mDeviceConfigPropertiesUpdated.close();
- // Update the callable to only close the properties updated condition when all the
- // desired properties have been updated. The DeviceConfig callbacks may happen multiple
- // times so testing the resulting updates is required.
- mShouldClosePropertiesUpdatedCallable = () -> {
- //noinspection deprecation
- return isEnabled() == enabledState;
- };
- if (mShouldClosePropertiesUpdatedCallable.call()) {
- return;
- }
+ // Update the callable to only close the properties updated condition when all the
+ // desired properties have been updated. The DeviceConfig callbacks may happen multiple
+ // times so testing the resulting updates is required.
+ waitForPropertiesCondition(() -> {
+ //noinspection deprecation
+ return isEnabled() == enabledState;
+ });
+ }
+
+ public void waitForPropertiesCondition(Callable<Boolean> shouldClosePropertiesUpdatedCallable)
+ throws Exception {
+ mShouldClosePropertiesUpdatedCallable.set(shouldClosePropertiesUpdatedCallable);
+ mDeviceConfigPropertiesUpdated.close();
+ if (!shouldClosePropertiesUpdatedCallable.call()) {
+ Log.i(TAG, "waiting for mDeviceConfigPropertiesUpdated condition");
+ mDeviceConfigPropertiesUpdated.block();
}
- Log.i(TAG, "waiting for condition");
- mDeviceConfigPropertiesUpdated.block();
+ Log.i(TAG, "waitForPropertiesCondition: returning");
}
}
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 2bb3cceb257f..39fb7936747e 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
@@ -22,7 +22,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
-import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
import android.util.SparseArray;
@@ -186,8 +185,9 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
mSyncQueue);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
- final DragPositioningCallback dragPositioningCallback = createDragPositioningCallback(
- windowDecoration, taskInfo);
+ final DragPositioningCallback dragPositioningCallback =
+ new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration, mDisplayController,
+ null /* disallowedAreaForEndBounds */);
final CaptionTouchEventListener touchEventListener =
new CaptionTouchEventListener(taskInfo, dragPositioningCallback);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
@@ -198,17 +198,6 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
setupCaptionColor(taskInfo, windowDecoration);
}
- private FluidResizeTaskPositioner createDragPositioningCallback(
- CaptionWindowDecoration windowDecoration, RunningTaskInfo taskInfo) {
- final int screenWidth = mDisplayController.getDisplayLayout(taskInfo.displayId).width();
- final int statusBarHeight = mDisplayController.getDisplayLayout(taskInfo.displayId)
- .stableInsets().top;
- final Rect disallowedAreaForEndBounds = new Rect(0, 0, screenWidth,
- statusBarHeight);
- return new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration,
- mDisplayController, disallowedAreaForEndBounds);
- }
-
private class CaptionTouchEventListener implements
View.OnClickListener, View.OnTouchListener, DragDetector.MotionEventHandler {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
index 9bcb77f03abd..9f79d212a7b9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
@@ -21,6 +21,8 @@ import android.graphics.Rect;
import android.view.SurfaceControl;
import android.window.WindowContainerTransaction;
+import androidx.annotation.Nullable;
+
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
@@ -42,24 +44,24 @@ class FluidResizeTaskPositioner implements DragPositioningCallback {
private final Rect mRepositionTaskBounds = new Rect();
// If a task move (not resize) finishes in this region, the positioner will not attempt to
// finalize the bounds there using WCT#setBounds
- private final Rect mDisallowedAreaForEndBounds = new Rect();
+ private final Rect mDisallowedAreaForEndBounds;
private boolean mHasDragResized;
private int mCtrlType;
FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
- DisplayController displayController, Rect disallowedAreaForEndBounds) {
+ DisplayController displayController, @Nullable Rect disallowedAreaForEndBounds) {
this(taskOrganizer, windowDecoration, displayController, disallowedAreaForEndBounds,
dragStartListener -> {}, SurfaceControl.Transaction::new);
}
FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
- DisplayController displayController, Rect disallowedAreaForEndBounds,
+ DisplayController displayController, @Nullable Rect disallowedAreaForEndBounds,
DragPositioningCallbackUtility.DragStartListener dragStartListener,
Supplier<SurfaceControl.Transaction> supplier) {
mTaskOrganizer = taskOrganizer;
mWindowDecoration = windowDecoration;
mDisplayController = displayController;
- mDisallowedAreaForEndBounds.set(disallowedAreaForEndBounds);
+ mDisallowedAreaForEndBounds = new Rect(disallowedAreaForEndBounds);
mDragStartListener = dragStartListener;
mTransactionSupplier = supplier;
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index b81339e85bcc..ba20a5e779fd 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -661,7 +661,7 @@ class CreateFlowUtils {
passwordCount = createEntry.getPasswordCredentialCount(),
passkeyCount = createEntry.getPublicKeyCredentialCount(),
totalCredentialCount = createEntry.getTotalCredentialCount(),
- lastUsedTime = createEntry.lastUsedTime,
+ lastUsedTime = createEntry.lastUsedTime ?: Instant.MIN,
footerDescription = createEntry.description?.toString()
))
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index fe1ce1b60413..8f3f3c87d93c 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -72,7 +72,7 @@ class CreateOptionInfo(
val passwordCount: Int?,
val passkeyCount: Int?,
val totalCredentialCount: Int?,
- val lastUsedTime: Instant?,
+ val lastUsedTime: Instant,
val footerDescription: String?,
) : BaseEntry(
providerId,
diff --git a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
index f050a1ef0f39..c85449d0c570 100644
--- a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
+++ b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
@@ -83,12 +83,5 @@
android:contentDescription="@string/data_connection_roaming"
android:visibility="gone" />
</FrameLayout>
- <ImageView
- android:id="@+id/mobile_roaming_large"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/stat_sys_roaming_large"
- android:contentDescription="@string/data_connection_roaming"
- android:visibility="gone" />
</com.android.keyguard.AlphaOptimizedLinearLayout>
</merge>
diff --git a/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml b/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
index 0cd062383570..8d35b237f31b 100644
--- a/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
@@ -25,4 +25,5 @@
android:scaleType="fitCenter"
android:tint="?android:attr/textColorPrimary"
android:src="@drawable/controls_icon"
+ android:elevation="@dimen/dream_overlay_bottom_affordance_elevation"
android:contentDescription="@string/quick_controls_title" />
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index 5552020f22cb..bfd079b59054 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -77,11 +77,4 @@
android:contentDescription="@string/data_connection_roaming"
android:visibility="gone" />
</FrameLayout>
- <ImageView
- android:id="@+id/mobile_roaming_large"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/stat_sys_roaming_large"
- android:contentDescription="@string/data_connection_roaming"
- android:visibility="gone" />
</com.android.keyguard.AlphaOptimizedLinearLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index bf0b8a660432..7488e9fbbe3e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1642,6 +1642,7 @@
<dimen name="dream_overlay_bottom_affordance_width">64dp</dimen>
<dimen name="dream_overlay_bottom_affordance_radius">32dp</dimen>
<dimen name="dream_overlay_bottom_affordance_padding">14dp</dimen>
+ <dimen name="dream_overlay_bottom_affordance_elevation">4dp</dimen>
<dimen name="dream_overlay_complication_clock_time_text_size">86dp</dimen>
<dimen name="dream_overlay_complication_clock_subtitle_text_size">24sp</dimen>
<dimen name="dream_overlay_complication_preview_text_size">36sp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 85788456d1cb..70c39df2a610 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -31,9 +31,6 @@ import android.os.Process;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.Dumpable;
-import android.util.DumpableContainer;
import android.util.Log;
import android.util.TimingsTraceLog;
import android.view.SurfaceControl;
@@ -57,18 +54,12 @@ import javax.inject.Provider;
* Application class for SystemUI.
*/
public class SystemUIApplication extends Application implements
- SystemUIAppComponentFactory.ContextInitializer, DumpableContainer {
+ SystemUIAppComponentFactory.ContextInitializer {
public static final String TAG = "SystemUIService";
private static final boolean DEBUG = false;
private BootCompleteCacheImpl mBootCompleteCache;
- private DumpManager mDumpManager;
-
- /**
- * Map of dumpables added externally.
- */
- private final ArrayMap<String, Dumpable> mDumpables = new ArrayMap<>();
/**
* Hold a reference on the stuff we start.
@@ -233,7 +224,7 @@ public class SystemUIApplication extends Application implements
}
}
- mDumpManager = mSysUIComponent.createDumpManager();
+ DumpManager dumpManager = mSysUIComponent.createDumpManager();
Log.v(TAG, "Starting SystemUI services for user " +
Process.myUserHandle().getIdentifier() + ".");
@@ -267,7 +258,7 @@ public class SystemUIApplication extends Application implements
notifyBootCompleted(mServices[i]);
}
- mDumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
+ dumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
}
mSysUIComponent.getInitController().executePostInitTasks();
log.traceEnd();
@@ -342,36 +333,6 @@ public class SystemUIApplication extends Application implements
return startable;
}
- // TODO(b/217567642): add unit tests? There doesn't seem to be a SystemUiApplicationTest...
- @Override
- public boolean addDumpable(Dumpable dumpable) {
- String name = dumpable.getDumpableName();
- if (mDumpables.containsKey(name)) {
- // This is normal because SystemUIApplication is an application context that is shared
- // among multiple components
- if (DEBUG) {
- Log.d(TAG, "addDumpable(): ignoring " + dumpable + " as there is already a dumpable"
- + " with that name (" + name + "): " + mDumpables.get(name));
- }
- return false;
- }
- if (DEBUG) Log.d(TAG, "addDumpable(): adding '" + name + "' = " + dumpable);
- mDumpables.put(name, dumpable);
-
- // TODO(b/217567642): replace com.android.systemui.dump.Dumpable by
- // com.android.util.Dumpable and get rid of the intermediate lambda
- mDumpManager.registerDumpable(dumpable.getDumpableName(), dumpable::dump);
- return true;
- }
-
- // TODO(b/217567642): implement
- @Override
- public boolean removeDumpable(Dumpable dumpable) {
- Log.w(TAG, "removeDumpable(" + dumpable + "): not implemented");
-
- return false;
- }
-
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (mServicesStarted) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt
index b72801d3b5fe..8edccf166efe 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt
@@ -21,7 +21,7 @@ constructor(
fun enable(onPanelInteraction: Runnable) {
if (action == null) {
action = Action(onPanelInteraction)
- shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged)
+ shadeExpansionStateManager.addShadeExpansionListener(this::onPanelExpansionChanged)
} else {
Log.e(TAG, "Already enabled")
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index a43f52019219..07259c2ff283 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -205,8 +205,11 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
// TODO move this logic to message queue
mCentralSurfacesOptionalLazy.get().ifPresent(centralSurfaces -> {
if (event.getActionMasked() == ACTION_DOWN) {
- centralSurfaces.getShadeViewController()
- .startExpandLatencyTracking();
+ ShadeViewController shadeViewController =
+ centralSurfaces.getShadeViewController();
+ if (shadeViewController != null) {
+ shadeViewController.startExpandLatencyTracking();
+ }
}
mHandler.post(() -> {
int action = event.getActionMasked();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
index 20313c3df465..a048f543d476 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
@@ -54,12 +54,20 @@ class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents {
* Listener will also be immediately notified with the current values.
*/
fun addExpansionListener(listener: ShadeExpansionListener) {
- expansionListeners.add(listener)
+ addShadeExpansionListener(listener)
listener.onPanelExpansionChanged(
ShadeExpansionChangeEvent(fraction, expanded, tracking, dragDownPxAmount)
)
}
+ /**
+ * Adds a listener that will be notified when the panel expansion fraction has changed.
+ * @see #addExpansionListener
+ */
+ fun addShadeExpansionListener(listener: ShadeExpansionListener) {
+ expansionListeners.add(listener)
+ }
+
/** Removes an expansion listener. */
fun removeExpansionListener(listener: ShadeExpansionListener) {
expansionListeners.remove(listener)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
index d9dc8878fa61..bbb4f2449330 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
@@ -236,7 +236,11 @@ constructor(
override fun postStartActivityDismissingKeyguard(intent: Intent, delay: Int) {
postOnUiThread(delay) {
- activityStarterInternal.startActivityDismissingKeyguard(intent = intent)
+ activityStarterInternal.startActivityDismissingKeyguard(
+ intent = intent,
+ onlyProvisioned = true,
+ dismissShade = true,
+ )
}
}
@@ -248,6 +252,8 @@ constructor(
postOnUiThread(delay) {
activityStarterInternal.startActivityDismissingKeyguard(
intent = intent,
+ onlyProvisioned = true,
+ dismissShade = true,
animationController = animationController,
)
}
@@ -262,6 +268,8 @@ constructor(
postOnUiThread(delay) {
activityStarterInternal.startActivityDismissingKeyguard(
intent = intent,
+ onlyProvisioned = true,
+ dismissShade = true,
animationController = animationController,
customMessage = customMessage,
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index 7aa90336e2bf..49de5a232f30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -160,7 +160,7 @@ abstract class StatusBarPipelineModule {
@SysUISingleton
@SharedConnectivityInputLog
fun provideSharedConnectivityTableLogBuffer(factory: LogBufferFactory): LogBuffer {
- return factory.create("SharedConnectivityInputLog", 30)
+ return factory.create("SharedConnectivityInputLog", 60)
}
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 0e9b6c56437e..81a068d10a14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -38,6 +38,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository
import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
@@ -88,6 +89,7 @@ constructor(
private val context: Context,
@Background private val bgDispatcher: CoroutineDispatcher,
@Application private val scope: CoroutineScope,
+ airplaneModeRepository: AirplaneModeRepository,
// Some "wifi networks" should be rendered as a mobile connection, which is why the wifi
// repository is an input to the mobile repository.
// See [CarrierMergedConnectionRepository] for details.
@@ -106,10 +108,20 @@ constructor(
context.getString(R.string.status_bar_network_name_separator)
private val carrierMergedSubId: StateFlow<Int?> =
- wifiRepository.wifiNetwork
- .mapLatest {
- if (it is WifiNetworkModel.CarrierMerged) {
- it.subscriptionId
+ combine(
+ wifiRepository.wifiNetwork,
+ connectivityRepository.defaultConnections,
+ airplaneModeRepository.isAirplaneMode,
+ ) { wifiNetwork, defaultConnections, isAirplaneMode ->
+ // The carrier merged connection should only be used if it's also the default
+ // connection or mobile connections aren't available because of airplane mode.
+ val defaultConnectionIsNonMobile =
+ defaultConnections.carrierMerged.isDefault ||
+ defaultConnections.wifi.isDefault ||
+ isAirplaneMode
+
+ if (wifiNetwork is WifiNetworkModel.CarrierMerged && defaultConnectionIsNonMobile) {
+ wifiNetwork.subscriptionId
} else {
null
}
@@ -269,12 +281,8 @@ constructor(
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
override val hasCarrierMergedConnection: StateFlow<Boolean> =
- combine(
- connectivityRepository.defaultConnections,
- carrierMergedSubId,
- ) { defaultConnections, carrierMergedSubId ->
- defaultConnections.carrierMerged.isDefault || carrierMergedSubId != null
- }
+ carrierMergedSubId
+ .map { it != null }
.distinctUntilChanged()
.logDiffsForTable(
tableLogger,
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index cd1ad1ba788f..316b54eb0c80 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -173,7 +173,7 @@ public class ImageWallpaper extends WallpaperService {
.isLockscreenLiveWallpaperEnabled();
mSurfaceHolder = surfaceHolder;
Rect dimensions = mIsLockscreenLiveWallpaperEnabled
- ? mWallpaperManager.peekBitmapDimensions(getSourceFlag())
+ ? mWallpaperManager.peekBitmapDimensions(getSourceFlag(), true)
: mWallpaperManager.peekBitmapDimensions();
int width = Math.max(MIN_SURFACE_WIDTH, dimensions.width());
int height = Math.max(MIN_SURFACE_HEIGHT, dimensions.height());
@@ -325,7 +325,7 @@ public class ImageWallpaper extends WallpaperService {
try {
bitmap = mIsLockscreenLiveWallpaperEnabled
? mWallpaperManager.getBitmapAsUser(
- mUserTracker.getUserId(), false, getSourceFlag())
+ mUserTracker.getUserId(), false, getSourceFlag(), true)
: mWallpaperManager.getBitmapAsUser(mUserTracker.getUserId(), false);
if (bitmap != null
&& bitmap.getByteCount() > RecordingCanvas.MAX_BITMAP_SIZE) {
@@ -347,7 +347,7 @@ public class ImageWallpaper extends WallpaperService {
try {
bitmap = mIsLockscreenLiveWallpaperEnabled
? mWallpaperManager.getBitmapAsUser(
- mUserTracker.getUserId(), false, getSourceFlag())
+ mUserTracker.getUserId(), false, getSourceFlag(), true)
: mWallpaperManager.getBitmapAsUser(mUserTracker.getUserId(), false);
} catch (RuntimeException | OutOfMemoryError e) {
Log.w(TAG, "Unable to load default wallpaper!", e);
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 21a7a340aa80..425d0bc47a4e 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,6 +39,7 @@ import android.testing.TestableLooper;
import android.util.FeatureFlagUtils;
import android.view.View;
+import androidx.annotation.NonNull;
import androidx.test.filters.MediumTest;
import com.android.internal.logging.UiEventLogger;
@@ -64,6 +65,7 @@ import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
+import java.util.function.Consumer;
@MediumTest
@RunWith(AndroidTestingRunner.class)
@@ -89,7 +91,7 @@ public class MediaOutputDialogTest extends SysuiTestCase {
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
private final MediaMetadata mMediaMetadata = mock(MediaMetadata.class);
- private final MediaDescription mMediaDescription = mock(MediaDescription.class);
+ private final MediaDescription mMediaDescription = mock(MediaDescription.class);
private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
NearbyMediaDevicesManager.class);
private final AudioManager mAudioManager = mock(AudioManager.class);
@@ -102,6 +104,11 @@ public class MediaOutputDialogTest extends SysuiTestCase {
private MediaOutputController mMediaOutputController;
private final List<String> mFeatures = new ArrayList<>();
+ @Override
+ protected boolean shouldFailOnLeakedReceiver() {
+ return true;
+ }
+
@Before
public void setUp() {
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
@@ -120,8 +127,7 @@ public class MediaOutputDialogTest extends SysuiTestCase {
Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
mKeyguardManager, mFlags);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
- mMediaOutputDialog = new MediaOutputDialog(mContext, false, mBroadcastSender,
- mMediaOutputController, mUiEventLogger);
+ mMediaOutputDialog = makeTestDialog(mMediaOutputController);
mMediaOutputDialog.show();
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice);
@@ -130,7 +136,7 @@ public class MediaOutputDialogTest extends SysuiTestCase {
@After
public void tearDown() {
- mMediaOutputDialog.dismissDialog();
+ mMediaOutputDialog.dismiss();
}
@Test
@@ -311,11 +317,9 @@ public class MediaOutputDialogTest extends SysuiTestCase {
MediaOutputController mockMediaOutputController = mock(MediaOutputController.class);
when(mockMediaOutputController.isBroadcastSupported()).thenReturn(false);
- MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false, mBroadcastSender,
- mockMediaOutputController, mUiEventLogger);
- testDialog.show();
-
- assertThat(testDialog.getStopButtonText().toString()).isEqualTo(stopText);
+ withTestDialog(mockMediaOutputController, testDialog -> {
+ assertThat(testDialog.getStopButtonText().toString()).isEqualTo(stopText);
+ });
}
@Test
@@ -328,11 +332,9 @@ public class MediaOutputDialogTest extends SysuiTestCase {
when(mockMediaOutputController.isBluetoothLeDevice(any())).thenReturn(true);
when(mockMediaOutputController.isPlaying()).thenReturn(true);
when(mockMediaOutputController.isBluetoothLeBroadcastEnabled()).thenReturn(false);
- MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false, mBroadcastSender,
- mockMediaOutputController, mUiEventLogger);
- testDialog.show();
-
- assertThat(testDialog.getStopButtonText().toString()).isEqualTo(stopText);
+ withTestDialog(mockMediaOutputController, testDialog -> {
+ assertThat(testDialog.getStopButtonText().toString()).isEqualTo(stopText);
+ });
}
@Test
@@ -341,11 +343,9 @@ public class MediaOutputDialogTest extends SysuiTestCase {
when(mockMediaOutputController.isBroadcastSupported()).thenReturn(false);
when(mockMediaOutputController.getCurrentConnectedMediaDevice()).thenReturn(null);
when(mockMediaOutputController.isPlaying()).thenReturn(false);
- MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false, mBroadcastSender,
- mockMediaOutputController, mUiEventLogger);
- testDialog.show();
-
- testDialog.onStopButtonClick();
+ withTestDialog(mockMediaOutputController, testDialog -> {
+ testDialog.onStopButtonClick();
+ });
verify(mockMediaOutputController).releaseSession();
}
@@ -354,13 +354,22 @@ public class MediaOutputDialogTest extends SysuiTestCase {
// Check the visibility metric logging by creating a new MediaOutput dialog,
// and verify if the calling times increases.
public void onCreate_ShouldLogVisibility() {
- MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false, mBroadcastSender,
- mMediaOutputController, mUiEventLogger);
- testDialog.show();
-
- testDialog.dismissDialog();
+ withTestDialog(mMediaOutputController, testDialog -> {});
verify(mUiEventLogger, times(2))
.log(MediaOutputDialog.MediaOutputEvent.MEDIA_OUTPUT_DIALOG_SHOW);
}
+
+ @NonNull
+ private MediaOutputDialog makeTestDialog(MediaOutputController controller) {
+ return new MediaOutputDialog(mContext, false, mBroadcastSender,
+ controller, mUiEventLogger);
+ }
+
+ private void withTestDialog(MediaOutputController controller, Consumer<MediaOutputDialog> c) {
+ MediaOutputDialog testDialog = makeTestDialog(controller);
+ testDialog.show();
+ c.accept(testDialog);
+ testDialog.dismiss();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
index b6b28c9e4527..4a3080050a37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
@@ -17,6 +17,7 @@ package com.android.systemui.statusbar.phone
import android.app.PendingIntent
import android.content.Intent
import android.os.RemoteException
+import android.os.UserHandle
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
@@ -102,6 +103,7 @@ class ActivityStarterImplTest : SysuiTestCase() {
activityIntentHelper,
mainExecutor,
)
+ whenever(userTracker.userHandle).thenReturn(UserHandle.OWNER)
}
@Test
@@ -150,11 +152,28 @@ class ActivityStarterImplTest : SysuiTestCase() {
@Test
fun postStartActivityDismissingKeyguard_intent_postsOnMain() {
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
val intent = mock(Intent::class.java)
underTest.postStartActivityDismissingKeyguard(intent, 0)
assertThat(mainExecutor.numPending()).isEqualTo(1)
+ mainExecutor.runAllReady()
+
+ verify(deviceProvisionedController).isDeviceProvisioned
+ verify(shadeController).runPostCollapseRunnables()
+ }
+
+ @Test
+ fun postStartActivityDismissingKeyguard_intent_notDeviceProvisioned_doesNotProceed() {
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(false)
+ val intent = mock(Intent::class.java)
+
+ underTest.postStartActivityDismissingKeyguard(intent, 0)
+ mainExecutor.runAllReady()
+
+ verify(deviceProvisionedController).isDeviceProvisioned
+ verify(shadeController, never()).runPostCollapseRunnables()
}
@Test
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 bde05b9f499e..5a887ebcee80 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
@@ -26,6 +26,7 @@ import com.android.systemui.demomode.DemoModeController
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepository
@@ -131,6 +132,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {
context,
IMMEDIATE,
scope,
+ FakeAirplaneModeRepository(),
wifiRepository,
mock(),
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 7cc59b67414b..38c7432eb288 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -34,13 +34,16 @@ import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import android.telephony.TelephonyCallback
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
import android.telephony.TelephonyManager
+import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.internal.telephony.PhoneConstants
import com.android.settingslib.R
import com.android.settingslib.mobile.MobileMappings
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
@@ -51,25 +54,25 @@ import com.android.systemui.statusbar.pipeline.mobile.util.FakeSubscriptionManag
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
-import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
+import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import java.util.UUID
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.yield
-import org.junit.After
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertThrows
import org.junit.Assert.assertTrue
import org.junit.Before
@@ -83,6 +86,9 @@ import org.mockito.MockitoAnnotations
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+// This is required because our [SubscriptionManager.OnSubscriptionsChangedListener] uses a looper
+// to run the callback and this makes the looper place nicely with TestScope etc.
+@TestableLooper.RunWithLooper
class MobileConnectionsRepositoryTest : SysuiTestCase() {
private lateinit var underTest: MobileConnectionsRepositoryImpl
@@ -90,7 +96,8 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
private lateinit var carrierMergedFactory: CarrierMergedConnectionRepository.Factory
private lateinit var fullConnectionFactory: FullMobileConnectionRepository.Factory
private lateinit var connectivityRepository: ConnectivityRepository
- private lateinit var wifiRepository: FakeWifiRepository
+ private lateinit var airplaneModeRepository: FakeAirplaneModeRepository
+ private lateinit var wifiRepository: WifiRepository
private lateinit var carrierConfigRepository: CarrierConfigRepository
@Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var subscriptionManager: SubscriptionManager
@@ -102,7 +109,8 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
private val mobileMappings = FakeMobileMappingsProxy()
private val subscriptionManagerProxy = FakeSubscriptionManagerProxy()
- private val scope = CoroutineScope(IMMEDIATE)
+ private val dispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(dispatcher)
@Before
fun setUp() {
@@ -138,11 +146,23 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
context,
mock(),
mock(),
- scope,
+ testScope.backgroundScope,
mock(),
)
- wifiRepository = FakeWifiRepository()
+ airplaneModeRepository = FakeAirplaneModeRepository()
+
+ wifiRepository =
+ WifiRepositoryImpl(
+ fakeBroadcastDispatcher,
+ connectivityManager,
+ connectivityRepository,
+ mock(),
+ mock(),
+ FakeExecutor(FakeSystemClock()),
+ testScope.backgroundScope,
+ mock(),
+ )
carrierConfigRepository =
CarrierConfigRepository(
@@ -150,28 +170,28 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
mock(),
mock(),
logger,
- scope,
+ testScope.backgroundScope,
)
connectionFactory =
MobileConnectionRepositoryImpl.Factory(
fakeBroadcastDispatcher,
telephonyManager = telephonyManager,
- bgDispatcher = IMMEDIATE,
+ bgDispatcher = dispatcher,
logger = logger,
mobileMappingsProxy = mobileMappings,
- scope = scope,
+ scope = testScope.backgroundScope,
carrierConfigRepository = carrierConfigRepository,
)
carrierMergedFactory =
CarrierMergedConnectionRepository.Factory(
telephonyManager,
- scope,
+ testScope.backgroundScope,
wifiRepository,
)
fullConnectionFactory =
FullMobileConnectionRepository.Factory(
- scope = scope,
+ scope = testScope.backgroundScope,
logFactory = logBufferFactory,
mobileRepoFactory = connectionFactory,
carrierMergedRepoFactory = carrierMergedFactory,
@@ -188,46 +208,38 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
mobileMappings,
fakeBroadcastDispatcher,
context,
- IMMEDIATE,
- scope,
+ dispatcher,
+ testScope.backgroundScope,
+ airplaneModeRepository,
wifiRepository,
fullConnectionFactory,
)
- }
- @After
- fun tearDown() {
- scope.cancel()
+ testScope.runCurrent()
}
@Test
fun testSubscriptions_initiallyEmpty() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
assertThat(underTest.subscriptions.value).isEqualTo(listOf<SubscriptionModel>())
}
@Test
fun testSubscriptions_listUpdates() =
- runBlocking(IMMEDIATE) {
- var latest: List<SubscriptionModel>? = null
-
- val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.subscriptions)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_2))
getSubscriptionCallback().onSubscriptionsChanged()
assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2))
-
- job.cancel()
}
@Test
fun testSubscriptions_removingSub_updatesList() =
- runBlocking(IMMEDIATE) {
- var latest: List<SubscriptionModel>? = null
-
- val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.subscriptions)
// WHEN 2 networks show up
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
@@ -241,71 +253,55 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
// THEN the subscriptions list represents the newest change
assertThat(latest).isEqualTo(listOf(MODEL_2))
-
- job.cancel()
}
@Test
fun testSubscriptions_carrierMergedOnly_listHasCarrierMerged() =
- runBlocking(IMMEDIATE) {
- var latest: List<SubscriptionModel>? = null
+ testScope.runTest {
+ val latest by collectLastValue(underTest.subscriptions)
- val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
-
- wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_CM))
getSubscriptionCallback().onSubscriptionsChanged()
assertThat(latest).isEqualTo(listOf(MODEL_CM))
-
- job.cancel()
}
@Test
fun testSubscriptions_carrierMergedAndOther_listHasBothWithCarrierMergedLast() =
- runBlocking(IMMEDIATE) {
- var latest: List<SubscriptionModel>? = null
+ testScope.runTest {
+ val latest by collectLastValue(underTest.subscriptions)
- val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
-
- wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_2, SUB_CM))
getSubscriptionCallback().onSubscriptionsChanged()
assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2, MODEL_CM))
-
- job.cancel()
}
@Test
fun testActiveDataSubscriptionId_initialValueIsNull() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
assertThat(underTest.activeMobileDataSubscriptionId.value).isEqualTo(null)
}
@Test
fun testActiveDataSubscriptionId_updates() =
- runBlocking(IMMEDIATE) {
- var active: Int? = null
-
- val job = underTest.activeMobileDataSubscriptionId.onEach { active = it }.launchIn(this)
+ testScope.runTest {
+ val active by collectLastValue(underTest.activeMobileDataSubscriptionId)
getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
.onActiveDataSubscriptionIdChanged(SUB_2_ID)
assertThat(active).isEqualTo(SUB_2_ID)
-
- job.cancel()
}
@Test
fun activeSubId_nullIfInvalidSubIdIsReceived() =
- runBlocking(IMMEDIATE) {
- var latest: Int? = null
-
- val job = underTest.activeMobileDataSubscriptionId.onEach { latest = it }.launchIn(this)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.activeMobileDataSubscriptionId)
getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
.onActiveDataSubscriptionIdChanged(SUB_2_ID)
@@ -316,8 +312,6 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
.onActiveDataSubscriptionIdChanged(INVALID_SUBSCRIPTION_ID)
assertThat(latest).isNull()
-
- job.cancel()
}
@Test
@@ -327,23 +321,19 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
@Test
fun activeRepo_updatesWithActiveDataId() =
- runBlocking(IMMEDIATE) {
- var latest: MobileConnectionRepository? = null
- val job = underTest.activeMobileDataRepository.onEach { latest = it }.launchIn(this)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.activeMobileDataRepository)
getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
.onActiveDataSubscriptionIdChanged(SUB_2_ID)
assertThat(latest?.subId).isEqualTo(SUB_2_ID)
-
- job.cancel()
}
@Test
fun activeRepo_nullIfActiveDataSubIdBecomesInvalid() =
- runBlocking(IMMEDIATE) {
- var latest: MobileConnectionRepository? = null
- val job = underTest.activeMobileDataRepository.onEach { latest = it }.launchIn(this)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.activeMobileDataRepository)
getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
.onActiveDataSubscriptionIdChanged(SUB_2_ID)
@@ -354,64 +344,49 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
.onActiveDataSubscriptionIdChanged(INVALID_SUBSCRIPTION_ID)
assertThat(latest).isNull()
-
- job.cancel()
}
@Test
/** Regression test for b/268146648. */
fun activeSubIdIsSetBeforeSubscriptionsAreUpdated_doesNotThrow() =
- runBlocking(IMMEDIATE) {
- var activeRepo: MobileConnectionRepository? = null
- var subscriptions: List<SubscriptionModel>? = null
-
- val activeRepoJob =
- underTest.activeMobileDataRepository.onEach { activeRepo = it }.launchIn(this)
- val subscriptionsJob =
- underTest.subscriptions.onEach { subscriptions = it }.launchIn(this)
+ testScope.runTest {
+ val activeRepo by collectLastValue(underTest.activeMobileDataRepository)
+ val subscriptions by collectLastValue(underTest.subscriptions)
getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
.onActiveDataSubscriptionIdChanged(SUB_2_ID)
assertThat(subscriptions).isEmpty()
assertThat(activeRepo).isNotNull()
-
- activeRepoJob.cancel()
- subscriptionsJob.cancel()
}
@Test
fun getRepoForSubId_activeDataSubIdIsRequestedBeforeSubscriptionsUpdate() =
- runBlocking(IMMEDIATE) {
- var latest: MobileConnectionRepository? = null
- var subscriptions: List<SubscriptionModel>? = null
- val activeSubIdJob =
- underTest.activeMobileDataSubscriptionId
- .filterNotNull()
- .onEach { latest = underTest.getRepoForSubId(it) }
- .launchIn(this)
- val subscriptionsJob =
- underTest.subscriptions.onEach { subscriptions = it }.launchIn(this)
+ testScope.runTest {
+ var latestActiveRepo: MobileConnectionRepository? = null
+ collectLastValue(
+ underTest.activeMobileDataSubscriptionId.filterNotNull().onEach {
+ latestActiveRepo = underTest.getRepoForSubId(it)
+ }
+ )
+
+ val latestSubscriptions by collectLastValue(underTest.subscriptions)
// Active data subscription id is sent, but no subscription change has been posted yet
getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
.onActiveDataSubscriptionIdChanged(SUB_2_ID)
// Subscriptions list is empty
- assertThat(subscriptions).isEmpty()
+ assertThat(latestSubscriptions).isEmpty()
// getRepoForSubId does not throw
- assertThat(latest).isNotNull()
-
- activeSubIdJob.cancel()
- subscriptionsJob.cancel()
+ assertThat(latestActiveRepo).isNotNull()
}
@Test
fun activeDataSentBeforeSubscriptionList_subscriptionReusesActiveDataRepo() =
- runBlocking(IMMEDIATE) {
- var activeRepo: MobileConnectionRepository? = null
- val job = underTest.activeMobileDataRepository.onEach { activeRepo = it }.launchIn(this)
- val subscriptionsJob = underTest.subscriptions.launchIn(this)
+ testScope.runTest {
+ val activeRepo by collectLastValue(underTest.activeMobileDataRepository)
+ collectLastValue(underTest.subscriptions)
// GIVEN active repo is updated before the subscription list updates
getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
@@ -429,15 +404,12 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
// THEN the newly request repo has been cached and reused
assertThat(activeRepo).isSameInstanceAs(newRepo)
-
- job.cancel()
- subscriptionsJob.cancel()
}
@Test
fun testConnectionRepository_validSubId_isCached() =
- runBlocking(IMMEDIATE) {
- val job = underTest.subscriptions.launchIn(this)
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1))
@@ -447,16 +419,15 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
val repo2 = underTest.getRepoForSubId(SUB_1_ID)
assertThat(repo1).isSameInstanceAs(repo2)
-
- job.cancel()
}
@Test
fun testConnectionRepository_carrierMergedSubId_isCached() =
- runBlocking(IMMEDIATE) {
- val job = underTest.subscriptions.launchIn(this)
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
- wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_CM))
getSubscriptionCallback().onSubscriptionsChanged()
@@ -465,16 +436,15 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
val repo2 = underTest.getRepoForSubId(SUB_CM_ID)
assertThat(repo1).isSameInstanceAs(repo2)
-
- job.cancel()
}
@Test
fun testConnectionRepository_carrierMergedAndMobileSubs_usesCorrectRepos() =
- runBlocking(IMMEDIATE) {
- val job = underTest.subscriptions.launchIn(this)
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
- wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_CM))
getSubscriptionCallback().onSubscriptionsChanged()
@@ -483,16 +453,15 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
val mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
-
- job.cancel()
}
@Test
fun testSubscriptions_subNoLongerCarrierMerged_repoUpdates() =
- runBlocking(IMMEDIATE) {
- val job = underTest.subscriptions.launchIn(this)
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
- wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_CM))
getSubscriptionCallback().onSubscriptionsChanged()
@@ -503,26 +472,28 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
// WHEN the wifi network updates to be not carrier merged
- wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = 4, level = 1))
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_ACTIVE)
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_ACTIVE)
+ runCurrent()
// THEN the repos update
val noLongerCarrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
assertThat(noLongerCarrierMergedRepo.getIsCarrierMerged()).isFalse()
assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
-
- job.cancel()
}
@Test
fun testSubscriptions_subBecomesCarrierMerged_repoUpdates() =
- runBlocking(IMMEDIATE) {
- val job = underTest.subscriptions.launchIn(this)
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
- wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_ACTIVE)
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_ACTIVE)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_CM))
getSubscriptionCallback().onSubscriptionsChanged()
+ runCurrent()
val notYetCarrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
var mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
@@ -530,21 +501,21 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
// WHEN the wifi network updates to be carrier merged
- wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ runCurrent()
// THEN the repos update
val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
-
- job.cancel()
}
@Test
fun testConnectionCache_clearsInvalidSubscriptions() =
- runBlocking(IMMEDIATE) {
- val job = underTest.subscriptions.launchIn(this)
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_2))
@@ -563,16 +534,15 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
getSubscriptionCallback().onSubscriptionsChanged()
assertThat(underTest.getSubIdRepoCache()).containsExactly(SUB_1_ID, repo1)
-
- job.cancel()
}
@Test
fun testConnectionCache_clearsInvalidSubscriptions_includingCarrierMerged() =
- runBlocking(IMMEDIATE) {
- val job = underTest.subscriptions.launchIn(this)
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
- wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_2, SUB_CM))
getSubscriptionCallback().onSubscriptionsChanged()
@@ -591,15 +561,13 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
getSubscriptionCallback().onSubscriptionsChanged()
assertThat(underTest.getSubIdRepoCache()).containsExactly(SUB_1_ID, repo1)
-
- job.cancel()
}
/** Regression test for b/261706421 */
@Test
fun testConnectionsCache_clearMultipleSubscriptionsAtOnce_doesNotThrow() =
- runBlocking(IMMEDIATE) {
- val job = underTest.subscriptions.launchIn(this)
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_2))
@@ -617,26 +585,20 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
getSubscriptionCallback().onSubscriptionsChanged()
assertThat(underTest.getSubIdRepoCache()).isEmpty()
-
- job.cancel()
}
@Test
fun testConnectionRepository_invalidSubId_throws() =
- runBlocking(IMMEDIATE) {
- val job = underTest.subscriptions.launchIn(this)
-
+ testScope.runTest {
assertThrows(IllegalArgumentException::class.java) {
underTest.getRepoForSubId(SUB_1_ID)
}
-
- job.cancel()
}
@Test
fun connectionRepository_logBufferContainsSubIdInItsName() =
- runBlocking(IMMEDIATE) {
- val job = underTest.subscriptions.launchIn(this)
+ testScope.runTest {
+ collectLastValue(underTest.subscriptions)
whenever(subscriptionManager.completeActiveSubscriptionInfoList)
.thenReturn(listOf(SUB_1, SUB_2))
@@ -655,15 +617,12 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
eq(tableBufferLogName(SUB_2_ID)),
anyInt(),
)
-
- job.cancel()
}
@Test
fun testDefaultDataSubId_updatesOnBroadcast() =
- runBlocking(IMMEDIATE) {
- var latest: Int? = null
- val job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.defaultDataSubId)
assertThat(latest).isEqualTo(INVALID_SUBSCRIPTION_ID)
@@ -686,28 +645,24 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
}
assertThat(latest).isEqualTo(SUB_1_ID)
-
- job.cancel()
}
@Test
fun defaultDataSubId_fetchesInitialValueOnStart() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
subscriptionManagerProxy.defaultDataSubId = 2
- var latest: Int? = null
- val job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultDataSubId)
assertThat(latest).isEqualTo(2)
-
- job.cancel()
}
@Test
fun defaultDataSubId_fetchesCurrentOnRestart() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
subscriptionManagerProxy.defaultDataSubId = 2
var latest: Int? = null
var job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
+ runCurrent()
assertThat(latest).isEqualTo(2)
@@ -720,6 +675,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
subscriptionManagerProxy.defaultDataSubId = 1
job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
+ runCurrent()
assertThat(latest).isEqualTo(1)
@@ -733,43 +689,37 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
@Test
fun mobileIsDefault_capsHaveCellular_isDefault() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
val caps =
mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
}
- var latest: Boolean? = null
- val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.mobileIsDefault)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
assertThat(latest).isTrue()
-
- job.cancel()
}
@Test
fun mobileIsDefault_capsDoNotHaveCellular_isNotDefault() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
val caps =
mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false)
}
- var latest: Boolean? = null
- val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.mobileIsDefault)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
assertThat(latest).isFalse()
-
- job.cancel()
}
@Test
fun mobileIsDefault_carrierMergedViaMobile_isDefault() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
val carrierMergedInfo =
mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
val caps =
@@ -778,151 +728,144 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
whenever(it.transportInfo).thenReturn(carrierMergedInfo)
}
- var latest: Boolean? = null
- val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.mobileIsDefault)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
assertThat(latest).isTrue()
-
- job.cancel()
}
@Test
fun mobileIsDefault_wifiDefault_mobileNotDefault() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
val caps =
mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
}
- var latest: Boolean? = null
- val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.mobileIsDefault)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
assertThat(latest).isFalse()
-
- job.cancel()
}
@Test
fun mobileIsDefault_ethernetDefault_mobileNotDefault() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
val caps =
mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(true)
}
- var latest: Boolean? = null
- val job = underTest.mobileIsDefault.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.mobileIsDefault)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
assertThat(latest).isFalse()
-
- job.cancel()
}
/** Regression test for b/272586234. */
@Test
fun hasCarrierMergedConnection_carrierMergedViaWifi_isTrue() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
val carrierMergedInfo =
- mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
+ mock<WifiInfo>().apply {
+ whenever(this.isCarrierMerged).thenReturn(true)
+ whenever(this.isPrimary).thenReturn(true)
+ }
val caps =
mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
whenever(it.transportInfo).thenReturn(carrierMergedInfo)
}
- var latest: Boolean? = null
- val job = underTest.hasCarrierMergedConnection.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.hasCarrierMergedConnection)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
- yield()
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
assertThat(latest).isTrue()
-
- job.cancel()
}
@Test
fun hasCarrierMergedConnection_carrierMergedViaMobile_isTrue() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
val carrierMergedInfo =
- mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
+ mock<WifiInfo>().apply {
+ whenever(this.isCarrierMerged).thenReturn(true)
+ whenever(this.isPrimary).thenReturn(true)
+ }
val caps =
mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
whenever(it.transportInfo).thenReturn(carrierMergedInfo)
}
- var latest: Boolean? = null
- val job = underTest.hasCarrierMergedConnection.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.hasCarrierMergedConnection)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
- yield()
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
assertThat(latest).isTrue()
-
- job.cancel()
}
/** Regression test for b/272586234. */
@Test
fun hasCarrierMergedConnection_carrierMergedViaWifiWithVcnTransport_isTrue() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
val carrierMergedInfo =
- mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
+ mock<WifiInfo>().apply {
+ whenever(this.isCarrierMerged).thenReturn(true)
+ whenever(this.isPrimary).thenReturn(true)
+ }
val caps =
mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo))
}
- var latest: Boolean? = null
- val job = underTest.hasCarrierMergedConnection.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.hasCarrierMergedConnection)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
- yield()
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
assertThat(latest).isTrue()
-
- job.cancel()
}
@Test
fun hasCarrierMergedConnection_carrierMergedViaMobileWithVcnTransport_isTrue() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
val carrierMergedInfo =
- mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
+ mock<WifiInfo>().apply {
+ whenever(this.isCarrierMerged).thenReturn(true)
+ whenever(this.isPrimary).thenReturn(true)
+ }
val caps =
mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
whenever(it.transportInfo).thenReturn(VcnTransportInfo(carrierMergedInfo))
}
- var latest: Boolean? = null
- val job = underTest.hasCarrierMergedConnection.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.hasCarrierMergedConnection)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
- yield()
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
assertThat(latest).isTrue()
-
- job.cancel()
}
@Test
fun hasCarrierMergedConnection_isCarrierMergedViaUnderlyingWifi_isTrue() =
- runBlocking(IMMEDIATE) {
- var latest: Boolean? = null
- val job = underTest.hasCarrierMergedConnection.onEach { latest = it }.launchIn(this)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.hasCarrierMergedConnection)
val underlyingNetwork = mock<Network>()
val carrierMergedInfo =
- mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
+ mock<WifiInfo>().apply {
+ whenever(this.isCarrierMerged).thenReturn(true)
+ whenever(this.isPrimary).thenReturn(true)
+ }
val underlyingWifiCapabilities =
mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
@@ -941,23 +884,23 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
}
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
- yield()
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
// THEN there's a carrier merged connection
assertThat(latest).isTrue()
-
- job.cancel()
}
@Test
fun hasCarrierMergedConnection_isCarrierMergedViaUnderlyingCellular_isTrue() =
- runBlocking(IMMEDIATE) {
- var latest: Boolean? = null
- val job = underTest.hasCarrierMergedConnection.onEach { latest = it }.launchIn(this)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.hasCarrierMergedConnection)
val underlyingCarrierMergedNetwork = mock<Network>()
val carrierMergedInfo =
- mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
+ mock<WifiInfo>().apply {
+ whenever(this.isCarrierMerged).thenReturn(true)
+ whenever(this.isPrimary).thenReturn(true)
+ }
val underlyingCapabilities =
mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
@@ -977,22 +920,19 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
}
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
- yield()
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
// THEN there's a carrier merged connection
assertThat(latest).isTrue()
-
- job.cancel()
}
/** Regression test for b/272586234. */
@Test
- fun hasCarrierMergedConnection_defaultNotCarrierMerged_butWifiRepoHasCarrierMerged_isTrue() =
- runBlocking(IMMEDIATE) {
- var latest: Boolean? = null
- val job = underTest.hasCarrierMergedConnection.onEach { latest = it }.launchIn(this)
+ fun hasCarrierMergedConnection_defaultIsWifiNotCarrierMerged_wifiRepoIsCarrierMerged_isTrue() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.hasCarrierMergedConnection)
- // WHEN the default callback isn't carrier merged
+ // WHEN the default callback is TRANSPORT_WIFI but not carrier merged
val carrierMergedInfo =
mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(false) }
val caps =
@@ -1001,16 +941,57 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
whenever(it.transportInfo).thenReturn(carrierMergedInfo)
}
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
- yield()
// BUT the wifi repo has gotten updates that it *is* carrier merged
- wifiRepository.setWifiNetwork(WIFI_NETWORK_CM)
- yield()
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
// THEN hasCarrierMergedConnection is true
assertThat(latest).isTrue()
+ }
- job.cancel()
+ /** Regression test for b/278618530. */
+ @Test
+ fun hasCarrierMergedConnection_defaultIsCellular_wifiRepoIsCarrierMerged_isFalse() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.hasCarrierMergedConnection)
+
+ // WHEN the default callback is TRANSPORT_CELLULAR and not carrier merged
+ val caps =
+ mock<NetworkCapabilities>().also {
+ whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+ whenever(it.transportInfo).thenReturn(null)
+ }
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+ // BUT the wifi repo has gotten updates that it *is* carrier merged
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+
+ // THEN hasCarrierMergedConnection is **false** (The default network being CELLULAR
+ // takes precedence over the wifi network being carrier merged.)
+ assertThat(latest).isFalse()
+ }
+
+ /** Regression test for b/278618530. */
+ @Test
+ fun hasCarrierMergedConnection_defaultCellular_wifiIsCarrierMerged_airplaneMode_isTrue() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.hasCarrierMergedConnection)
+
+ // WHEN the default callback is TRANSPORT_CELLULAR and not carrier merged
+ val caps =
+ mock<NetworkCapabilities>().also {
+ whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+ whenever(it.transportInfo).thenReturn(null)
+ }
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+ // BUT the wifi repo has gotten updates that it *is* carrier merged
+ getNormalNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+ // AND we're in airplane mode
+ airplaneModeRepository.setIsAirplaneMode(true)
+
+ // THEN hasCarrierMergedConnection is true.
+ assertThat(latest).isTrue()
}
@Test
@@ -1020,43 +1001,37 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
@Test
fun defaultConnectionIsValidated_capsHaveValidated_isValidated() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
val caps =
mock<NetworkCapabilities>().also {
whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(true)
}
- var latest: Boolean? = null
- val job = underTest.defaultConnectionIsValidated.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnectionIsValidated)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
assertThat(latest).isTrue()
-
- job.cancel()
}
@Test
fun defaultConnectionIsValidated_capsHaveNotValidated_isNotValidated() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
val caps =
mock<NetworkCapabilities>().also {
whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(false)
}
- var latest: Boolean? = null
- val job = underTest.defaultConnectionIsValidated.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnectionIsValidated)
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
assertThat(latest).isFalse()
-
- job.cancel()
}
@Test
fun config_initiallyFromContext() =
- runBlocking(IMMEDIATE) {
+ testScope.runTest {
overrideResource(R.bool.config_showMin3G, true)
val configFromContext = MobileMappings.Config.readConfig(context)
assertThat(configFromContext.showAtLeast3G).isTrue()
@@ -1074,26 +1049,24 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
mobileMappings,
fakeBroadcastDispatcher,
context,
- IMMEDIATE,
- scope,
+ dispatcher,
+ testScope.backgroundScope,
+ airplaneModeRepository,
wifiRepository,
fullConnectionFactory,
)
- var latest: MobileMappings.Config? = null
- val job = underTest.defaultDataSubRatConfig.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultDataSubRatConfig)
assertTrue(latest!!.areEqual(configFromContext))
assertTrue(latest!!.showAtLeast3G)
-
- job.cancel()
}
@Test
fun config_subIdChangeEvent_updated() =
- runBlocking(IMMEDIATE) {
- var latest: MobileMappings.Config? = null
- val job = underTest.defaultDataSubRatConfig.onEach { latest = it }.launchIn(this)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.defaultDataSubRatConfig)
+
assertThat(latest!!.showAtLeast3G).isFalse()
overrideResource(R.bool.config_showMin3G, true)
@@ -1112,15 +1085,13 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
// THEN the config is updated
assertTrue(latest!!.areEqual(configFromContext))
assertTrue(latest!!.showAtLeast3G)
-
- job.cancel()
}
@Test
fun config_carrierConfigChangeEvent_updated() =
- runBlocking(IMMEDIATE) {
- var latest: MobileMappings.Config? = null
- val job = underTest.defaultDataSubRatConfig.onEach { latest = it }.launchIn(this)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.defaultDataSubRatConfig)
+
assertThat(latest!!.showAtLeast3G).isFalse()
overrideResource(R.bool.config_showMin3G, true)
@@ -1138,15 +1109,12 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
// THEN the config is updated
assertThat(latest!!.areEqual(configFromContext)).isTrue()
assertThat(latest!!.showAtLeast3G).isTrue()
-
- job.cancel()
}
@Test
fun activeDataChange_inSameGroup_emitsUnit() =
- runBlocking(IMMEDIATE) {
- var latest: Unit? = null
- val job = underTest.activeSubChangedInGroupEvent.onEach { latest = it }.launchIn(this)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.activeSubChangedInGroupEvent)
getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
.onActiveDataSubscriptionIdChanged(SUB_3_ID_GROUPED)
@@ -1154,15 +1122,12 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
.onActiveDataSubscriptionIdChanged(SUB_4_ID_GROUPED)
assertThat(latest).isEqualTo(Unit)
-
- job.cancel()
}
@Test
fun activeDataChange_notInSameGroup_doesNotEmit() =
- runBlocking(IMMEDIATE) {
- var latest: Unit? = null
- val job = underTest.activeSubChangedInGroupEvent.onEach { latest = it }.launchIn(this)
+ testScope.runTest {
+ val latest by collectLastValue(underTest.activeSubChangedInGroupEvent)
getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
.onActiveDataSubscriptionIdChanged(SUB_3_ID_GROUPED)
@@ -1170,38 +1135,46 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
.onActiveDataSubscriptionIdChanged(SUB_1_ID)
assertThat(latest).isEqualTo(null)
-
- job.cancel()
}
- private fun getDefaultNetworkCallback(): ConnectivityManager.NetworkCallback {
+ private fun TestScope.getDefaultNetworkCallback(): ConnectivityManager.NetworkCallback {
+ runCurrent()
val callbackCaptor = argumentCaptor<ConnectivityManager.NetworkCallback>()
verify(connectivityManager).registerDefaultNetworkCallback(callbackCaptor.capture())
return callbackCaptor.value!!
}
- private fun getSubscriptionCallback(): SubscriptionManager.OnSubscriptionsChangedListener {
+ // Note: This is used to update the [WifiRepository].
+ private fun TestScope.getNormalNetworkCallback(): ConnectivityManager.NetworkCallback {
+ runCurrent()
+ val callbackCaptor = argumentCaptor<ConnectivityManager.NetworkCallback>()
+ verify(connectivityManager).registerNetworkCallback(any(), callbackCaptor.capture())
+ return callbackCaptor.value!!
+ }
+
+ private fun TestScope.getSubscriptionCallback():
+ SubscriptionManager.OnSubscriptionsChangedListener {
+ runCurrent()
val callbackCaptor = argumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener>()
verify(subscriptionManager)
.addOnSubscriptionsChangedListener(any(), callbackCaptor.capture())
return callbackCaptor.value!!
}
- private fun getTelephonyCallbacks(): List<TelephonyCallback> {
+ private fun TestScope.getTelephonyCallbacks(): List<TelephonyCallback> {
+ runCurrent()
val callbackCaptor = argumentCaptor<TelephonyCallback>()
verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
return callbackCaptor.allValues
}
- private inline fun <reified T> getTelephonyCallbackForType(): T {
- val cbs = getTelephonyCallbacks().filterIsInstance<T>()
+ private inline fun <reified T> TestScope.getTelephonyCallbackForType(): T {
+ val cbs = this.getTelephonyCallbacks().filterIsInstance<T>()
assertThat(cbs.size).isEqualTo(1)
return cbs[0]
}
companion object {
- private val IMMEDIATE = Dispatchers.Main.immediate
-
// Subscription 1
private const val SUB_1_ID = 1
private val GROUP_1 = ParcelUuid(UUID.randomUUID())
@@ -1259,11 +1232,30 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
private val SUB_CM =
mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_CM_ID) }
private val MODEL_CM = SubscriptionModel(subscriptionId = SUB_CM_ID)
- private val WIFI_NETWORK_CM =
- WifiNetworkModel.CarrierMerged(
- networkId = 3,
- subscriptionId = SUB_CM_ID,
- level = 1,
- )
+
+ private val WIFI_INFO_CM =
+ mock<WifiInfo>().apply {
+ whenever(this.isPrimary).thenReturn(true)
+ whenever(this.isCarrierMerged).thenReturn(true)
+ whenever(this.subscriptionId).thenReturn(SUB_CM_ID)
+ }
+ private val WIFI_NETWORK_CAPS_CM =
+ mock<NetworkCapabilities>().also {
+ whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+ whenever(it.transportInfo).thenReturn(WIFI_INFO_CM)
+ whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(true)
+ }
+
+ private val WIFI_INFO_ACTIVE =
+ mock<WifiInfo>().apply {
+ whenever(this.isPrimary).thenReturn(true)
+ whenever(this.isCarrierMerged).thenReturn(false)
+ }
+ private val WIFI_NETWORK_CAPS_ACTIVE =
+ mock<NetworkCapabilities>().also {
+ whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+ whenever(it.transportInfo).thenReturn(WIFI_INFO_ACTIVE)
+ whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(true)
+ }
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index 1ec4e8c48707..8bbd58dc8fe1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -102,7 +102,8 @@ public abstract class SysuiTestCase {
mock(Executor.class),
mock(DumpManager.class),
mock(BroadcastDispatcherLogger.class),
- mock(UserTracker.class));
+ mock(UserTracker.class),
+ shouldFailOnLeakedReceiver());
mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
Instrumentation inst = spy(mRealInstrumentation);
@@ -141,6 +142,10 @@ public abstract class SysuiTestCase {
mDependency.injectTestDependency(DialogLaunchAnimator.class, fakeDialogLaunchAnimator());
}
+ protected boolean shouldFailOnLeakedReceiver() {
+ return false;
+ }
+
@After
public void SysuiTeardown() {
if (mRealInstrumentation != null) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
index ad086ff9c664..af940e4fa687 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
@@ -27,6 +27,7 @@ import com.android.systemui.SysuiTestableContext
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
import com.android.systemui.dump.DumpManager
import com.android.systemui.settings.UserTracker
+import java.lang.IllegalStateException
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executor
@@ -37,7 +38,8 @@ class FakeBroadcastDispatcher(
broadcastRunningExecutor: Executor,
dumpManager: DumpManager,
logger: BroadcastDispatcherLogger,
- userTracker: UserTracker
+ userTracker: UserTracker,
+ private val shouldFailOnLeakedReceiver: Boolean
) :
BroadcastDispatcher(
context,
@@ -85,6 +87,9 @@ class FakeBroadcastDispatcher(
fun cleanUpReceivers(testName: String) {
registeredReceivers.forEach {
Log.i(testName, "Receiver not unregistered from dispatcher: $it")
+ if (shouldFailOnLeakedReceiver) {
+ throw IllegalStateException("Receiver not unregistered from dispatcher: $it")
+ }
}
registeredReceivers.clear()
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8ce1829a4b16..5d3bb31bc31f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7511,7 +7511,31 @@ public class ActivityManagerService extends IActivityManager.Stub
"registerUidObserver");
}
mUidObserverController.register(observer, which, cutpoint, callingPackage,
- Binder.getCallingUid());
+ Binder.getCallingUid(), /*uids*/null);
+ }
+
+ /**
+ * Registers a UidObserver with a uid filter.
+ *
+ * @param observer The UidObserver implementation to register.
+ * @param which A bitmask of events to observe. See ActivityManager.UID_OBSERVER_*.
+ * @param cutpoint The cutpoint for onUidStateChanged events. When the state crosses this
+ * threshold in either direction, onUidStateChanged will be called.
+ * @param callingPackage The name of the calling package.
+ * @param uids A list of uids to watch. If all uids are to be watched, use
+ * registerUidObserver instead.
+ * @throws RemoteException
+ * @return Returns A binder token identifying the UidObserver registration.
+ */
+ @Override
+ public IBinder registerUidObserverForUids(IUidObserver observer, int which, int cutpoint,
+ String callingPackage, int[] uids) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+ "registerUidObserver");
+ }
+ return mUidObserverController.register(observer, which, cutpoint, callingPackage,
+ Binder.getCallingUid(), uids);
}
@Override
@@ -7519,6 +7543,40 @@ public class ActivityManagerService extends IActivityManager.Stub
mUidObserverController.unregister(observer);
}
+ /**
+ * Adds a uid to the list of uids that a UidObserver will receive updates about.
+ *
+ * @param observerToken The binder token identifying the UidObserver registration.
+ * @param callingPackage The name of the calling package.
+ * @param uid The uid to watch.
+ * @throws RemoteException
+ */
+ @Override
+ public void addUidToObserver(IBinder observerToken, String callingPackage, int uid) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+ "registerUidObserver");
+ }
+ mUidObserverController.addUidToObserver(observerToken, uid);
+ }
+
+ /**
+ * Removes a uid from the list of uids that a UidObserver will receive updates about.
+ *
+ * @param observerToken The binder token identifying the UidObserver registration.
+ * @param callingPackage The name of the calling package.
+ * @param uid The uid to stop watching.
+ * @throws RemoteException
+ */
+ @Override
+ public void removeUidFromObserver(IBinder observerToken, String callingPackage, int uid) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+ "registerUidObserver");
+ }
+ mUidObserverController.removeUidFromObserver(observerToken, uid);
+ }
+
@Override
public boolean isUidActive(int uid, String callingPackage) {
if (!hasUsageStatsPermission(callingPackage)) {
@@ -18613,7 +18671,7 @@ public class ActivityManagerService extends IActivityManager.Stub
int which, int cutpoint, @NonNull String callingPackage) {
mNetworkPolicyUidObserver = observer;
mUidObserverController.register(observer, which, cutpoint, callingPackage,
- Binder.getCallingUid());
+ Binder.getCallingUid(), /*uids*/null);
}
@Override
diff --git a/services/core/java/com/android/server/am/UidObserverController.java b/services/core/java/com/android/server/am/UidObserverController.java
index 790cc7b87f80..5e41dcd0009e 100644
--- a/services/core/java/com/android/server/am/UidObserverController.java
+++ b/services/core/java/com/android/server/am/UidObserverController.java
@@ -27,7 +27,9 @@ import android.app.ActivityManager;
import android.app.ActivityManagerProto;
import android.app.IUidObserver;
import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -43,6 +45,8 @@ import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserve
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.UUID;
public class UidObserverController {
/** If a UID observer takes more than this long, send a WTF. */
@@ -79,14 +83,19 @@ public class UidObserverController {
mValidateUids = new ActiveUids(null /* service */, false /* postChangesToAtm */);
}
- void register(@NonNull IUidObserver observer, int which, int cutpoint,
- @NonNull String callingPackage, int callingUid) {
+ IBinder register(@NonNull IUidObserver observer, int which, int cutpoint,
+ @NonNull String callingPackage, int callingUid, @Nullable int[] uids) {
+ IBinder token = new Binder("UidObserver-" + callingPackage + "-"
+ + UUID.randomUUID().toString());
+
synchronized (mLock) {
mUidObservers.register(observer, new UidObserverRegistration(callingUid,
callingPackage, which, cutpoint,
ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, callingUid)
- == PackageManager.PERMISSION_GRANTED));
+ == PackageManager.PERMISSION_GRANTED, uids, token));
}
+
+ return token;
}
void unregister(@NonNull IUidObserver observer) {
@@ -95,6 +104,42 @@ public class UidObserverController {
}
}
+ void addUidToObserver(@NonNull IBinder observerToken, int uid) {
+ synchronized (mLock) {
+ int i = mUidObservers.beginBroadcast();
+ while (i-- > 0) {
+ var reg = (UidObserverRegistration) mUidObservers.getBroadcastCookie(i);
+ if (reg.getToken().equals(observerToken)) {
+ reg.addUid(uid);
+ break;
+ }
+
+ if (i == 0) {
+ Slog.e(TAG_UID_OBSERVERS, "Unable to find UidObserver by token");
+ }
+ }
+ mUidObservers.finishBroadcast();
+ }
+ }
+
+ void removeUidFromObserver(@NonNull IBinder observerToken, int uid) {
+ synchronized (mLock) {
+ int i = mUidObservers.beginBroadcast();
+ while (i-- > 0) {
+ var reg = (UidObserverRegistration) mUidObservers.getBroadcastCookie(i);
+ if (reg.getToken().equals(observerToken)) {
+ reg.removeUid(uid);
+ break;
+ }
+
+ if (i == 0) {
+ Slog.e(TAG_UID_OBSERVERS, "Unable to find UidObserver by token");
+ }
+ }
+ mUidObservers.finishBroadcast();
+ }
+ }
+
int enqueueUidChange(@Nullable ChangeRecord currentRecord, int uid, int change, int procState,
int procAdj, long procStateSeq, int capability, boolean ephemeral) {
synchronized (mLock) {
@@ -257,6 +302,10 @@ public class UidObserverController {
final ChangeRecord item = mActiveUidChanges[j];
final long start = SystemClock.uptimeMillis();
final int change = item.change;
+ // Is the observer watching this uid?
+ if (!reg.isWatchingUid(item.uid)) {
+ continue;
+ }
// Does the user have permission? Don't send a non user UID change otherwise
if (UserHandle.getUserId(item.uid) != UserHandle.getUserId(reg.mUid)
&& !reg.mCanInteractAcrossUsers) {
@@ -450,6 +499,8 @@ public class UidObserverController {
private final int mWhich;
private final int mCutpoint;
private final boolean mCanInteractAcrossUsers;
+ private final IBinder mToken;
+ private int[] mUids;
/**
* Total # of callback calls that took more than {@link #SLOW_UID_OBSERVER_THRESHOLD_MS}.
@@ -481,16 +532,94 @@ public class UidObserverController {
};
UidObserverRegistration(int uid, @NonNull String pkg, int which, int cutpoint,
- boolean canInteractAcrossUsers) {
+ boolean canInteractAcrossUsers, @Nullable int[] uids, @NonNull IBinder token) {
this.mUid = uid;
this.mPkg = pkg;
this.mWhich = which;
this.mCutpoint = cutpoint;
this.mCanInteractAcrossUsers = canInteractAcrossUsers;
+
+ if (uids != null) {
+ this.mUids = uids.clone();
+ Arrays.sort(this.mUids);
+ } else {
+ this.mUids = null;
+ }
+
+ this.mToken = token;
+
mLastProcStates = cutpoint >= ActivityManager.MIN_PROCESS_STATE
? new SparseIntArray() : null;
}
+ boolean isWatchingUid(int uid) {
+ if (mUids == null) {
+ return true;
+ }
+
+ return Arrays.binarySearch(mUids, uid) != -1;
+ }
+
+ void addUid(int uid) {
+ if (mUids == null) {
+ return;
+ }
+
+ int[] temp = mUids;
+ mUids = new int[temp.length + 1];
+ boolean inserted = false;
+ for (int i = 0; i < temp.length; i++) {
+ if (!inserted) {
+ if (temp[i] < uid) {
+ mUids[i] = temp[i];
+ } else if (temp[i] == uid) {
+ // Duplicate uid, no-op and fallback to the previous array
+ mUids = temp;
+ return;
+ } else {
+ mUids[i] = uid;
+ mUids[i + 1] = temp[i];
+ inserted = true;
+ }
+ } else {
+ mUids[i + 1] = temp[i];
+ }
+ }
+
+ if (!inserted) {
+ mUids[temp.length] = uid;
+ }
+ }
+
+ void removeUid(int uid) {
+ if (mUids == null || mUids.length == 0) {
+ return;
+ }
+
+ int[] temp = mUids;
+ mUids = new int[temp.length - 1];
+ boolean removed = false;
+ for (int i = 0; i < temp.length; i++) {
+ if (!removed) {
+ if (temp[i] == uid) {
+ removed = true;
+ } else if (i == temp.length - 1) {
+ // Uid not found, no-op and fallback to the previous array
+ mUids = temp;
+ return;
+ } else {
+ mUids[i] = temp[i];
+ }
+ } else {
+ mUids[i - 1] = temp[i];
+ }
+ }
+ }
+
+ IBinder getToken() {
+ return mToken;
+ }
+
void dump(@NonNull PrintWriter pw, @NonNull IUidObserver observer) {
pw.print(" ");
UserHandle.formatUid(pw, mUid);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 6f640700949e..84d3a216ac91 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2789,6 +2789,20 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
/**
+ * Returns true if there is a static wallpaper on the specified screen. With which=FLAG_LOCK,
+ * always return false if the lockscreen doesn't run its own wallpaper engine.
+ */
+ @Override
+ public boolean isStaticWallpaper(int which) {
+ synchronized (mLock) {
+ WallpaperData wallpaperData = (which == FLAG_LOCK ? mLockWallpaperMap : mWallpaperMap)
+ .get(mCurrentUserId);
+ if (wallpaperData == null) return false;
+ return mImageWallpaper.equals(wallpaperData.wallpaperComponent);
+ }
+ }
+
+ /**
* Sets wallpaper dim amount for the calling UID. This applies to all destinations (home, lock)
* with an active wallpaper engine.
*
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8baf048980ed..f253fb0c7271 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3922,15 +3922,17 @@ public class WindowManagerService extends IWindowManager.Stub
/**
* Returns the touch mode state for the display id passed as argument.
+ *
+ * This method will return the default touch mode state (represented by
+ * {@code com.android.internal.R.bool.config_defaultInTouchMode}) if the display passed as
+ * argument is no longer registered in {@RootWindowContainer}).
*/
@Override // Binder call
public boolean isInTouchMode(int displayId) {
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent == null) {
- throw new IllegalStateException("Failed to retrieve the touch mode state for"
- + "display {" + displayId + "}: display is not registered in "
- + "WindowRootContainer");
+ return mContext.getResources().getBoolean(R.bool.config_defaultInTouchMode);
}
return displayContent.isInTouchMode();
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
index 1f0346a2b9d6..d4b88001111e 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
@@ -132,7 +132,8 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS
protected void invokeSession() {
if (mRemoteCredentialService != null) {
startCandidateMetrics();
- mRemoteCredentialService.onClearCredentialState(mProviderRequest, this);
+ mRemoteCredentialService.setCallback(this);
+ mRemoteCredentialService.onClearCredentialState(mProviderRequest);
}
}
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index 16beaa4eb13e..409806a21679 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -248,7 +248,8 @@ public final class ProviderCreateSession extends ProviderSession<
protected void invokeSession() {
if (mRemoteCredentialService != null) {
startCandidateMetrics();
- mRemoteCredentialService.onBeginCreateCredential(mProviderRequest, this);
+ mRemoteCredentialService.setCallback(this);
+ mRemoteCredentialService.onBeginCreateCredential(mProviderRequest);
}
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 1e80703378e0..64438e338e5b 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -309,7 +309,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
protected void invokeSession() {
if (mRemoteCredentialService != null) {
startCandidateMetrics();
- mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this);
+ mRemoteCredentialService.setCallback(this);
+ mRemoteCredentialService.onBeginGetCredential(mProviderRequest);
}
}
diff --git a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
index 83e7e939e064..4bcf8be0d21e 100644
--- a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
+++ b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
@@ -48,6 +48,7 @@ import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -66,6 +67,10 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
private final ComponentName mComponentName;
+ private AtomicBoolean mOngoingRequest = new AtomicBoolean(false);
+
+ @Nullable private ProviderCallbacks mCallback;
+
/**
* Callbacks to be invoked when the provider remote service responds with a
* success or failure.
@@ -94,12 +99,35 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
mComponentName = componentName;
}
+ public void setCallback(ProviderCallbacks callback) {
+ mCallback = callback;
+ }
+
/** Unbinds automatically after this amount of time. */
@Override
protected long getAutoDisconnectTimeoutMs() {
return TIMEOUT_IDLE_SERVICE_CONNECTION_MILLIS;
}
+ @Override
+ public void onBindingDied(ComponentName name) {
+ super.onBindingDied(name);
+
+ Slog.w(TAG, "binding died for: " + name);
+ }
+
+ @Override
+ public void binderDied() {
+ super.binderDied();
+ Slog.w(TAG, "binderDied");
+
+ if (mCallback != null) {
+ mOngoingRequest.set(false);
+ mCallback.onProviderServiceDied(this);
+ }
+
+ }
+
/** Return the componentName of the service to be connected. */
@NonNull
public ComponentName getComponentName() {
@@ -116,11 +144,14 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
* provider service.
*
* @param request the request to be sent to the provider
- * @param callback the callback to be used to send back the provider response to the
- * {@link ProviderGetSession} class that maintains provider state
*/
- public void onBeginGetCredential(@NonNull BeginGetCredentialRequest request,
- ProviderCallbacks<BeginGetCredentialResponse> callback) {
+ public void onBeginGetCredential(@NonNull BeginGetCredentialRequest request) {
+ if (mCallback == null) {
+ Slog.w(TAG, "Callback is not set");
+ return;
+ }
+ mOngoingRequest.set(true);
+
AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
AtomicReference<CompletableFuture<BeginGetCredentialResponse>> futureRef =
new AtomicReference<>();
@@ -154,7 +185,9 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
dispatchCancellationSignal(cancellation);
} else {
cancellationSink.set(cancellation);
- callback.onProviderCancellable(cancellation);
+ if (mCallback != null) {
+ mCallback.onProviderCancellable(cancellation);
+ }
}
}
});
@@ -166,7 +199,7 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
futureRef.set(connectThenExecute);
connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() ->
- handleExecutionResponse(result, error, cancellationSink, callback)));
+ handleExecutionResponse(result, error, cancellationSink)));
}
/**
@@ -174,11 +207,14 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
* provider service.
*
* @param request the request to be sent to the provider
- * @param callback the callback to be used to send back the provider response to the
- * {@link ProviderCreateSession} class that maintains provider state
*/
- public void onBeginCreateCredential(@NonNull BeginCreateCredentialRequest request,
- ProviderCallbacks<BeginCreateCredentialResponse> callback) {
+ public void onBeginCreateCredential(@NonNull BeginCreateCredentialRequest request) {
+ if (mCallback == null) {
+ Slog.w(TAG, "Callback is not set");
+ return;
+ }
+ mOngoingRequest.set(true);
+
AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
AtomicReference<CompletableFuture<BeginCreateCredentialResponse>> futureRef =
new AtomicReference<>();
@@ -212,7 +248,9 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
dispatchCancellationSignal(cancellation);
} else {
cancellationSink.set(cancellation);
- callback.onProviderCancellable(cancellation);
+ if (mCallback != null) {
+ mCallback.onProviderCancellable(cancellation);
+ }
}
}
});
@@ -224,7 +262,7 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
futureRef.set(connectThenExecute);
connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() ->
- handleExecutionResponse(result, error, cancellationSink, callback)));
+ handleExecutionResponse(result, error, cancellationSink)));
}
/**
@@ -232,11 +270,14 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
* provider service.
*
* @param request the request to be sent to the provider
- * @param callback the callback to be used to send back the provider response to the
- * {@link ProviderClearSession} class that maintains provider state
*/
- public void onClearCredentialState(@NonNull ClearCredentialStateRequest request,
- ProviderCallbacks<Void> callback) {
+ public void onClearCredentialState(@NonNull ClearCredentialStateRequest request) {
+ if (mCallback == null) {
+ Slog.w(TAG, "Callback is not set");
+ return;
+ }
+ mOngoingRequest.set(true);
+
AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
AtomicReference<CompletableFuture<Void>> futureRef = new AtomicReference<>();
@@ -269,7 +310,9 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
dispatchCancellationSignal(cancellation);
} else {
cancellationSink.set(cancellation);
- callback.onProviderCancellable(cancellation);
+ if (mCallback != null) {
+ mCallback.onProviderCancellable(cancellation);
+ }
}
}
});
@@ -281,40 +324,58 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
futureRef.set(connectThenExecute);
connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() ->
- handleExecutionResponse(result, error, cancellationSink, callback)));
+ handleExecutionResponse(result, error, cancellationSink)));
}
private <T> void handleExecutionResponse(T result,
Throwable error,
- AtomicReference<ICancellationSignal> cancellationSink,
- ProviderCallbacks<T> callback) {
+ AtomicReference<ICancellationSignal> cancellationSink) {
if (error == null) {
- callback.onProviderResponseSuccess(result);
+ if (mCallback != null) {
+ mCallback.onProviderResponseSuccess(result);
+ }
} else {
if (error instanceof TimeoutException) {
Slog.i(TAG, "Remote provider response timed tuo for: " + mComponentName);
+ if (!mOngoingRequest.get()) {
+ return;
+ }
dispatchCancellationSignal(cancellationSink.get());
- callback.onProviderResponseFailure(
- CredentialProviderErrors.ERROR_TIMEOUT,
- null);
+ if (mCallback != null) {
+ mOngoingRequest.set(false);
+ mCallback.onProviderResponseFailure(
+ CredentialProviderErrors.ERROR_TIMEOUT, null);
+ }
} else if (error instanceof CancellationException) {
Slog.i(TAG, "Cancellation exception for remote provider: " + mComponentName);
+ if (!mOngoingRequest.get()) {
+ return;
+ }
dispatchCancellationSignal(cancellationSink.get());
- callback.onProviderResponseFailure(
- CredentialProviderErrors.ERROR_TASK_CANCELED,
- null);
+ if (mCallback != null) {
+ mOngoingRequest.set(false);
+ mCallback.onProviderResponseFailure(
+ CredentialProviderErrors.ERROR_TASK_CANCELED,
+ null);
+ }
} else if (error instanceof GetCredentialException) {
- callback.onProviderResponseFailure(
- CredentialProviderErrors.ERROR_PROVIDER_FAILURE,
- (GetCredentialException) error);
+ if (mCallback != null) {
+ mCallback.onProviderResponseFailure(
+ CredentialProviderErrors.ERROR_PROVIDER_FAILURE,
+ (GetCredentialException) error);
+ }
} else if (error instanceof CreateCredentialException) {
- callback.onProviderResponseFailure(
- CredentialProviderErrors.ERROR_PROVIDER_FAILURE,
- (CreateCredentialException) error);
+ if (mCallback != null) {
+ mCallback.onProviderResponseFailure(
+ CredentialProviderErrors.ERROR_PROVIDER_FAILURE,
+ (CreateCredentialException) error);
+ }
} else {
- callback.onProviderResponseFailure(
- CredentialProviderErrors.ERROR_UNKNOWN,
- (Exception) error);
+ if (mCallback != null) {
+ mCallback.onProviderResponseFailure(
+ CredentialProviderErrors.ERROR_UNKNOWN,
+ (Exception) error);
+ }
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
index 46974cf72381..37afc7f52f7e 100644
--- a/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UidObserverControllerTest.java
@@ -217,7 +217,8 @@ public class UidObserverControllerTest {
private void registerObserver(IUidObserver observer, int which, int cutpoint,
String callingPackage, int callingUid) {
when(observer.asBinder()).thenReturn((IBinder) observer);
- mUidObserverController.register(observer, which, cutpoint, callingPackage, callingUid);
+ mUidObserverController.register(observer, which, cutpoint, callingPackage, callingUid,
+ /*uids*/null);
Mockito.reset(observer);
}
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
index 385c28ae7152..6a1674b7df8e 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
@@ -38,7 +38,6 @@ import android.os.BatteryStatsInternal;
import android.os.Process;
import android.os.RemoteException;
-import androidx.test.filters.FlakyTest;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.internal.util.FakeLatencyTracker;
@@ -92,12 +91,10 @@ public class SoundTriggerMiddlewareLoggingLatencyTest {
}
@Test
- @FlakyTest(bugId = 275113847)
public void testSetUpAndTearDown() {
}
@Test
- @FlakyTest(bugId = 275113847)
public void testOnPhraseRecognitionStartsLatencyTrackerWithSuccessfulPhraseIdTrigger()
throws RemoteException {
ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
@@ -114,7 +111,6 @@ public class SoundTriggerMiddlewareLoggingLatencyTest {
}
@Test
- @FlakyTest(bugId = 275113847)
public void testOnPhraseRecognitionRestartsActiveSession() throws RemoteException {
ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
ISoundTriggerCallback.class);
@@ -135,7 +131,6 @@ public class SoundTriggerMiddlewareLoggingLatencyTest {
}
@Test
- @FlakyTest(bugId = 275113847)
public void testOnPhraseRecognitionNeverStartsLatencyTrackerWithNonSuccessEvent()
throws RemoteException {
ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
@@ -153,7 +148,6 @@ public class SoundTriggerMiddlewareLoggingLatencyTest {
}
@Test
- @FlakyTest(bugId = 275113847)
public void testOnPhraseRecognitionNeverStartsLatencyTrackerWithNoKeyphraseId()
throws RemoteException {
ArgumentCaptor<ISoundTriggerCallback> soundTriggerCallbackCaptor = ArgumentCaptor.forClass(
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 58bf184994e4..d3f68185a269 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -67,7 +67,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.pm.ActivityInfo;
-import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.VirtualDisplay;
@@ -515,12 +514,8 @@ public class WindowManagerServiceTests extends WindowTestsBase {
@Test
public void testSetInTouchMode_instrumentedProcessGetPermissionToSwitchTouchMode() {
- // Disable global touch mode (config_perDisplayFocusEnabled set to true)
- Resources mockResources = mock(Resources.class);
- spyOn(mContext);
- when(mContext.getResources()).thenReturn(mockResources);
- doReturn(true).when(mockResources).getBoolean(
- com.android.internal.R.bool.config_perDisplayFocusEnabled);
+ // Enable global touch mode
+ mWm.mPerDisplayFocusEnabled = true;
// Get current touch mode state and setup WMS to run setInTouchMode
boolean currentTouchMode = mWm.isInTouchMode(DEFAULT_DISPLAY);
@@ -539,12 +534,8 @@ public class WindowManagerServiceTests extends WindowTestsBase {
@Test
public void testSetInTouchMode_nonInstrumentedProcessDontGetPermissionToSwitchTouchMode() {
- // Disable global touch mode (config_perDisplayFocusEnabled set to true)
- Resources mockResources = mock(Resources.class);
- spyOn(mContext);
- when(mContext.getResources()).thenReturn(mockResources);
- doReturn(true).when(mockResources).getBoolean(
- com.android.internal.R.bool.config_perDisplayFocusEnabled);
+ // Enable global touch mode
+ mWm.mPerDisplayFocusEnabled = true;
// Get current touch mode state and setup WMS to run setInTouchMode
boolean currentTouchMode = mWm.isInTouchMode(DEFAULT_DISPLAY);
@@ -563,6 +554,9 @@ public class WindowManagerServiceTests extends WindowTestsBase {
@Test
public void testSetInTouchMode_multiDisplay_globalTouchModeUpdate() {
+ // Disable global touch mode
+ mWm.mPerDisplayFocusEnabled = false;
+
// Create one extra display
final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false);
final VirtualDisplay virtualDisplayOwnTouchMode =
@@ -570,17 +564,10 @@ public class WindowManagerServiceTests extends WindowTestsBase {
final int numberOfDisplays = mWm.mRoot.mChildren.size();
assertThat(numberOfDisplays).isAtLeast(3);
final int numberOfGlobalTouchModeDisplays = (int) mWm.mRoot.mChildren.stream()
- .filter(d -> (d.getDisplay().getFlags() & FLAG_OWN_FOCUS) == 0)
- .count();
+ .filter(d -> (d.getDisplay().getFlags() & FLAG_OWN_FOCUS) == 0)
+ .count();
assertThat(numberOfGlobalTouchModeDisplays).isAtLeast(2);
- // Enable global touch mode (config_perDisplayFocusEnabled set to false)
- Resources mockResources = mock(Resources.class);
- spyOn(mContext);
- when(mContext.getResources()).thenReturn(mockResources);
- doReturn(false).when(mockResources).getBoolean(
- com.android.internal.R.bool.config_perDisplayFocusEnabled);
-
// Get current touch mode state and setup WMS to run setInTouchMode
boolean currentTouchMode = mWm.isInTouchMode(DEFAULT_DISPLAY);
int callingPid = Binder.getCallingPid();
@@ -598,18 +585,14 @@ public class WindowManagerServiceTests extends WindowTestsBase {
@Test
public void testSetInTouchMode_multiDisplay_perDisplayFocus_singleDisplayTouchModeUpdate() {
+ // Enable global touch mode
+ mWm.mPerDisplayFocusEnabled = true;
+
// Create one extra display
final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false);
final int numberOfDisplays = mWm.mRoot.mChildren.size();
assertThat(numberOfDisplays).isAtLeast(2);
- // Disable global touch mode (config_perDisplayFocusEnabled set to true)
- Resources mockResources = mock(Resources.class);
- spyOn(mContext);
- when(mContext.getResources()).thenReturn(mockResources);
- doReturn(true).when(mockResources).getBoolean(
- com.android.internal.R.bool.config_perDisplayFocusEnabled);
-
// Get current touch mode state and setup WMS to run setInTouchMode
boolean currentTouchMode = mWm.isInTouchMode(DEFAULT_DISPLAY);
int callingPid = Binder.getCallingPid();
@@ -628,18 +611,14 @@ public class WindowManagerServiceTests extends WindowTestsBase {
@Test
public void testSetInTouchMode_multiDisplay_ownTouchMode_singleDisplayTouchModeUpdate() {
+ // Disable global touch mode
+ mWm.mPerDisplayFocusEnabled = false;
+
// Create one extra display
final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ true);
final int numberOfDisplays = mWm.mRoot.mChildren.size();
assertThat(numberOfDisplays).isAtLeast(2);
- // Enable global touch mode (config_perDisplayFocusEnabled set to false)
- Resources mockResources = mock(Resources.class);
- spyOn(mContext);
- when(mContext.getResources()).thenReturn(mockResources);
- doReturn(false).when(mockResources).getBoolean(
- com.android.internal.R.bool.config_perDisplayFocusEnabled);
-
// Get current touch mode state and setup WMS to run setInTouchMode
boolean currentTouchMode = mWm.isInTouchMode(DEFAULT_DISPLAY);
int callingPid = Binder.getCallingPid();
@@ -667,19 +646,14 @@ public class WindowManagerServiceTests extends WindowTestsBase {
}
private void testSetInTouchModeOnAllDisplays(boolean perDisplayFocusEnabled) {
+ // Set global touch mode with the value passed as argument.
+ mWm.mPerDisplayFocusEnabled = perDisplayFocusEnabled;
+
// Create a couple of extra displays.
// setInTouchModeOnAllDisplays should ignore the ownFocus setting.
final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false);
final VirtualDisplay virtualDisplayOwnFocus = createVirtualDisplay(/* ownFocus= */ true);
- // Enable or disable global touch mode (config_perDisplayFocusEnabled setting).
- // setInTouchModeOnAllDisplays should ignore this value.
- Resources mockResources = mock(Resources.class);
- spyOn(mContext);
- when(mContext.getResources()).thenReturn(mockResources);
- doReturn(perDisplayFocusEnabled).when(mockResources).getBoolean(
- com.android.internal.R.bool.config_perDisplayFocusEnabled);
-
int callingPid = Binder.getCallingPid();
int callingUid = Binder.getCallingUid();
doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index a4cad5e24dc1..863523f826b2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -197,6 +197,8 @@ class WindowTestsBase extends SystemServiceTestsBase {
*/
private static boolean sOverridesCheckedTestDisplay;
+ private boolean mOriginalPerDisplayFocusEnabled;
+
@BeforeClass
public static void setUpOnceBase() {
AttributeCache.init(getInstrumentation().getTargetContext());
@@ -208,6 +210,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
mSupervisor = mAtm.mTaskSupervisor;
mRootWindowContainer = mAtm.mRootWindowContainer;
mWm = mSystemServicesTestRule.getWindowManagerService();
+ mOriginalPerDisplayFocusEnabled = mWm.mPerDisplayFocusEnabled;
SystemServicesTestRule.checkHoldsLock(mWm.mGlobalLock);
mDefaultDisplay = mWm.mRoot.getDefaultDisplay();
@@ -279,6 +282,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
if (mUseFakeSettingsProvider) {
FakeSettingsProvider.clearSettingsProvider();
}
+ mWm.mPerDisplayFocusEnabled = mOriginalPerDisplayFocusEnabled;
}
/**