Merge "AudioDeviceInventory: fix purge of device role cache." into udc-dev
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 2198fcd..f67c68e 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -111,20 +111,20 @@
float pathErrorScale) throws NotFoundException {
final ConfigurationBoundResourceCache<Animator> animatorCache = resources
.getAnimatorCache();
- ConfigurationBoundResourceCache.Entry<Animator> animatorEntry =
- animatorCache.getInstance(id, resources, theme);
- if (animatorEntry.hasValue()) {
+ Animator animator = animatorCache.getInstance(id, resources, theme);
+ if (animator != null) {
if (DBG_ANIMATOR_INFLATER) {
Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id));
}
- return animatorEntry.getValue();
+ return animator;
} else if (DBG_ANIMATOR_INFLATER) {
Log.d(TAG, "cache miss for animator " + resources.getResourceName(id));
}
+ int cacheGeneration = animatorCache.getGeneration();
XmlResourceParser parser = null;
try {
parser = resources.getAnimation(id);
- Animator animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale);
+ animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale);
if (animator != null) {
animator.appendChangingConfigurations(getChangingConfigs(resources, id));
final ConstantState<Animator> constantState = animator.createConstantState();
@@ -132,7 +132,7 @@
if (DBG_ANIMATOR_INFLATER) {
Log.d(TAG, "caching animator for res " + resources.getResourceName(id));
}
- animatorCache.put(id, theme, constantState, animatorEntry.getGeneration());
+ animatorCache.put(id, theme, constantState, cacheGeneration);
// create a new animator so that cached version is never used by the user
animator = constantState.newInstance(resources, theme);
}
@@ -161,22 +161,22 @@
final ConfigurationBoundResourceCache<StateListAnimator> cache = resources
.getStateListAnimatorCache();
final Theme theme = context.getTheme();
- ConfigurationBoundResourceCache.Entry<StateListAnimator> animatorEntry =
- cache.getInstance(id, resources, theme);
- if (animatorEntry.hasValue()) {
- return animatorEntry.getValue();
+ StateListAnimator animator = cache.getInstance(id, resources, theme);
+ if (animator != null) {
+ return animator;
}
+ int cacheGeneration = cache.getGeneration();
XmlResourceParser parser = null;
try {
parser = resources.getAnimation(id);
- StateListAnimator animator =
+ animator =
createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
if (animator != null) {
animator.appendChangingConfigurations(getChangingConfigs(resources, id));
final ConstantState<StateListAnimator> constantState = animator
.createConstantState();
if (constantState != null) {
- cache.put(id, theme, constantState, animatorEntry.getGeneration());
+ cache.put(id, theme, constantState, cacheGeneration);
// return a clone so that the animator in constant state is never used.
animator = constantState.newInstance(resources, theme);
}
diff --git a/core/java/android/app/admin/WifiSsidPolicy.java b/core/java/android/app/admin/WifiSsidPolicy.java
index ed53967..ffc4480 100644
--- a/core/java/android/app/admin/WifiSsidPolicy.java
+++ b/core/java/android/app/admin/WifiSsidPolicy.java
@@ -136,7 +136,7 @@
}
/**
- * Two instances of WifiSsidPolicy is considered equal if they have
+ * Two instances of WifiSsidPolicy are considered equal if they have
* the same WifiSsidPolicyType and the same set of WifiSsids
*/
@Override
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 960d10a..048289f 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2628,15 +2628,6 @@
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
- // STOPSHIP: hack for the pre-release SDK
- if (platformSdkCodenames.length == 0
- && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
- targetCode)) {
- Slog.w(TAG, "Package requires development platform " + targetCode
- + ", returning current version " + Build.VERSION.SDK_INT);
- return Build.VERSION.SDK_INT;
- }
-
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + targetCode
@@ -2708,15 +2699,6 @@
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
- // STOPSHIP: hack for the pre-release SDK
- if (platformSdkCodenames.length == 0
- && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
- minCode)) {
- Slog.w(TAG, "Package requires min development platform " + minCode
- + ", returning current version " + Build.VERSION.SDK_INT);
- return Build.VERSION.SDK_INT;
- }
-
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + minCode
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 8cc4cdb..3e1c5bb 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -316,15 +316,6 @@
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
- // STOPSHIP: hack for the pre-release SDK
- if (platformSdkCodenames.length == 0
- && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
- minCode)) {
- Slog.w(TAG, "Parsed package requires min development platform " + minCode
- + ", returning current version " + Build.VERSION.SDK_INT);
- return input.success(Build.VERSION.SDK_INT);
- }
-
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
@@ -377,27 +368,19 @@
return input.success(targetVers);
}
- // If it's a pre-release SDK and the codename matches this platform, it
- // definitely targets this SDK.
- if (matchTargetCode(platformSdkCodenames, targetCode)) {
- return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
- }
-
- // STOPSHIP: hack for the pre-release SDK
- if (platformSdkCodenames.length == 0
- && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
- targetCode)) {
- Slog.w(TAG, "Parsed package requires development platform " + targetCode
- + ", returning current version " + Build.VERSION.SDK_INT);
- return input.success(Build.VERSION.SDK_INT);
- }
-
try {
if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) {
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
} catch (IllegalArgumentException e) {
- return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, "Bad package SDK");
+ // isAtMost() throws it when encountering an older SDK codename
+ return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, e.getMessage());
+ }
+
+ // If it's a pre-release SDK and the codename matches this platform, it
+ // definitely targets this SDK.
+ if (matchTargetCode(platformSdkCodenames, targetCode)) {
+ return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
// Otherwise, we're looking at an incompatible pre-release SDK.
diff --git a/core/java/android/content/res/ConfigurationBoundResourceCache.java b/core/java/android/content/res/ConfigurationBoundResourceCache.java
index 4da3c18..5e10a57 100644
--- a/core/java/android/content/res/ConfigurationBoundResourceCache.java
+++ b/core/java/android/content/res/ConfigurationBoundResourceCache.java
@@ -37,16 +37,16 @@
* @param key a key that uniquely identifies the drawable resource
* @param resources a Resources object from which to create new instances.
* @param theme the theme where the resource will be used
- * @return an Entry wrapping a new instance of the resource, or {@code null} if not in
+ * @return a new instance of the resource, or {@code null} if not in
* the cache
*/
- public Entry<T> getInstance(long key, Resources resources, Resources.Theme theme) {
- final Entry<ConstantState<T>> e = get(key, theme);
- if (e.hasValue()) {
- return new Entry<>(e.getValue().newInstance(resources, theme), e.getGeneration());
+ public T getInstance(long key, Resources resources, Resources.Theme theme) {
+ final ConstantState<T> entry = get(key, theme);
+ if (entry != null) {
+ return entry.newInstance(resources, theme);
}
- return new Entry<>(null, e.getGeneration());
+ return null;
}
@Override
diff --git a/core/java/android/content/res/DrawableCache.java b/core/java/android/content/res/DrawableCache.java
index b51d14a..d0ebe33 100644
--- a/core/java/android/content/res/DrawableCache.java
+++ b/core/java/android/content/res/DrawableCache.java
@@ -40,32 +40,14 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Drawable getInstance(long key, Resources resources, Resources.Theme theme) {
- final Entry<Drawable.ConstantState> entry = get(key, theme);
- if (entry.getValue() != null) {
- return entry.getValue().newDrawable(resources, theme);
+ final Drawable.ConstantState entry = get(key, theme);
+ if (entry != null) {
+ return entry.newDrawable(resources, theme);
}
return null;
}
- /**
- * If the resource is cached, creates and returns a new instance of it.
- *
- * @param key a key that uniquely identifies the drawable resource
- * @param resources a Resources object from which to create new instances.
- * @param theme the theme where the resource will be used
- * @return an Entry wrapping a a new instance of the resource, or {@code null} if not in
- * the cache
- */
- public Entry<Drawable> getDrawable(long key, Resources resources, Resources.Theme theme) {
- final Entry<Drawable.ConstantState> e = get(key, theme);
- if (e.hasValue()) {
- return new Entry<>(e.getValue().newDrawable(resources, theme), e.getGeneration());
- }
-
- return new Entry<>(null, e.getGeneration());
- }
-
@Override
public boolean shouldInvalidateEntry(Drawable.ConstantState entry, int configChanges) {
return Configuration.needNewResources(configChanges, entry.getChangingConfigurations());
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 25154d5..1fdfcd0 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -650,21 +650,16 @@
key = (((long) value.assetCookie) << 32) | value.data;
}
- int cacheGeneration;
+ int cacheGeneration = caches.getGeneration();
// First, check whether we have a cached version of this drawable
// that was inflated against the specified theme. Skip the cache if
// we're currently preloading or we're not using the cache.
if (!mPreloading && useCache) {
- final ThemedResourceCache.Entry<Drawable> cachedDrawable =
- caches.getDrawable(key, wrapper, theme);
- if (cachedDrawable.hasValue()) {
- cachedDrawable.getValue().setChangingConfigurations(
- value.changingConfigurations);
- return cachedDrawable.getValue();
+ Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
+ if (cachedDrawable != null) {
+ cachedDrawable.setChangingConfigurations(value.changingConfigurations);
+ return cachedDrawable;
}
- cacheGeneration = cachedDrawable.getGeneration();
- } else {
- cacheGeneration = ThemedResourceCache.UNDEFINED_GENERATION;
}
// Next, check preloaded drawables. Preloaded drawables may contain
@@ -1009,16 +1004,15 @@
TypedValue value, int id) {
final long key = (((long) value.assetCookie) << 32) | value.data;
final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
- ThemedResourceCache.Entry<ComplexColor> complexColorEntry =
- cache.getInstance(key, wrapper, theme);
- if (complexColorEntry.hasValue()) {
- return complexColorEntry.getValue();
+ ComplexColor complexColor = cache.getInstance(key, wrapper, theme);
+ if (complexColor != null) {
+ return complexColor;
}
+ int cacheGeneration = cache.getGeneration();
final android.content.res.ConstantState<ComplexColor> factory =
sPreloadedComplexColors.get(key);
- ComplexColor complexColor = null;
if (factory != null) {
complexColor = factory.newInstance(wrapper, theme);
}
@@ -1035,8 +1029,7 @@
sPreloadedComplexColors.put(key, complexColor.getConstantState());
}
} else {
- cache.put(key, theme, complexColor.getConstantState(),
- complexColorEntry.getGeneration());
+ cache.put(key, theme, complexColor.getConstantState(), cacheGeneration);
}
}
return complexColor;
diff --git a/core/java/android/content/res/ThemedResourceCache.java b/core/java/android/content/res/ThemedResourceCache.java
index e7fd275..a7cd168 100644
--- a/core/java/android/content/res/ThemedResourceCache.java
+++ b/core/java/android/content/res/ThemedResourceCache.java
@@ -41,29 +41,6 @@
private int mGeneration;
- public static class Entry<S> {
- private S mValue;
- private int mGeneration;
-
-
- public S getValue() {
- return mValue;
- }
-
- public boolean hasValue() {
- return mValue != null;
- }
-
- public int getGeneration() {
- return mGeneration;
- }
-
- Entry(S value, int generation) {
- this.mValue = value;
- this.mGeneration = generation;
- }
- }
-
/**
* Adds a new theme-dependent entry to the cache.
*
@@ -109,6 +86,15 @@
}
/**
+ * Returns the current generation of the cache
+ *
+ * @return The current generation
+ */
+ public int getGeneration() {
+ return mGeneration;
+ }
+
+ /**
* Returns an entry from the cache.
*
* @param key a key that uniquely identifies the entry
@@ -116,7 +102,7 @@
* @return a cached entry, or {@code null} if not in the cache
*/
@Nullable
- public Entry get(long key, @Nullable Theme theme) {
+ public T get(long key, @Nullable Theme theme) {
// The themed (includes null-themed) and unthemed caches are mutually
// exclusive, so we'll give priority to whichever one we think we'll
// hit first. Since most of the framework drawables are themed, that's
@@ -126,7 +112,7 @@
if (themedEntries != null) {
final WeakReference<T> themedEntry = themedEntries.get(key);
if (themedEntry != null) {
- return new Entry(themedEntry.get(), mGeneration);
+ return themedEntry.get();
}
}
@@ -134,14 +120,15 @@
if (unthemedEntries != null) {
final WeakReference<T> unthemedEntry = unthemedEntries.get(key);
if (unthemedEntry != null) {
- return new Entry(unthemedEntry.get(), mGeneration);
+ return unthemedEntry.get();
}
}
}
- return new Entry(null, mGeneration);
+ return null;
}
+
/**
* Prunes cache entries that have been invalidated by a configuration
* change.
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index d87226c..65d4b43 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -77,18 +77,18 @@
private static final String TAG = "CameraAdvancedExtensionSessionImpl";
private final Executor mExecutor;
- private final CameraDevice mCameraDevice;
+ private CameraDevice mCameraDevice;
private final Map<String, CameraMetadataNative> mCharacteristicsMap;
private final long mExtensionClientId;
private final Handler mHandler;
private final HandlerThread mHandlerThread;
private final CameraExtensionSession.StateCallback mCallbacks;
- private final IAdvancedExtenderImpl mAdvancedExtender;
+ private IAdvancedExtenderImpl mAdvancedExtender;
// maps registered camera surfaces to extension output configs
private final HashMap<Surface, CameraOutputConfig> mCameraConfigMap = new HashMap<>();
// maps camera extension output ids to camera registered image readers
private final HashMap<Integer, ImageReader> mReaderMap = new HashMap<>();
- private final RequestProcessor mRequestProcessor = new RequestProcessor();
+ private RequestProcessor mRequestProcessor = new RequestProcessor();
private final int mSessionId;
private Surface mClientRepeatingRequestSurface;
@@ -100,7 +100,7 @@
private final ExtensionSessionStatsAggregator mStatsAggregator;
private boolean mInitialized;
-
+ private boolean mSessionClosed;
// Lock to synchronize cross-thread access to device public interface
final Object mInterfaceLock;
@@ -237,6 +237,7 @@
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
mInitialized = false;
+ mSessionClosed = false;
mInitializeHandler = new InitializeSessionHandler();
mSessionId = sessionId;
mInterfaceLock = cameraDevice.mInterfaceLock;
@@ -424,7 +425,7 @@
mSessionProcessor.setParameters(request);
seqId = mSessionProcessor.startRepeating(new RequestCallbackHandler(request,
- executor, listener));
+ executor, listener, mCameraDevice.getId()));
} catch (RemoteException e) {
throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
"Failed to enable repeating request, extension service failed to respond!");
@@ -452,7 +453,7 @@
mSessionProcessor.setParameters(request);
seqId = mSessionProcessor.startCapture(new RequestCallbackHandler(request,
- executor, listener), isPostviewRequested);
+ executor, listener, mCameraDevice.getId()), isPostviewRequested);
} catch (RemoteException e) {
throw new CameraAccessException(CameraAccessException.CAMERA_ERROR, "Failed " +
" to submit capture request, extension service failed to respond!");
@@ -460,8 +461,8 @@
} else if ((mClientRepeatingRequestSurface != null) &&
request.containsTarget(mClientRepeatingRequestSurface)) {
try {
- seqId = mSessionProcessor.startTrigger(request,
- new RequestCallbackHandler(request, executor, listener));
+ seqId = mSessionProcessor.startTrigger(request, new RequestCallbackHandler(
+ request, executor, listener, mCameraDevice.getId()));
} catch (RemoteException e) {
throw new CameraAccessException(CameraAccessException.CAMERA_ERROR, "Failed " +
" to submit trigger request, extension service failed to respond!");
@@ -528,6 +529,7 @@
mCaptureSession.stopRepeating();
mSessionProcessor.stopRepeating();
mSessionProcessor.onCaptureSessionEnd();
+ mSessionClosed = true;
} catch (RemoteException e) {
Log.e(TAG, "Failed to stop the repeating request or end the session,"
+ " , extension service does not respond!") ;
@@ -560,6 +562,9 @@
if (mSessionProcessor != null) {
try {
+ if (!mSessionClosed) {
+ mSessionProcessor.onCaptureSessionEnd();
+ }
mSessionProcessor.deInitSession();
} catch (RemoteException e) {
Log.e(TAG, "Failed to de-initialize session processor, extension service"
@@ -584,6 +589,10 @@
mClientRepeatingRequestSurface = null;
mClientCaptureSurface = null;
+ mCaptureSession = null;
+ mRequestProcessor = null;
+ mCameraDevice = null;
+ mAdvancedExtender = null;
}
if (notifyClose && !skipCloseNotification) {
@@ -706,13 +715,16 @@
private final CaptureRequest mClientRequest;
private final Executor mClientExecutor;
private final ExtensionCaptureCallback mClientCallbacks;
+ private final String mCameraId;
private RequestCallbackHandler(@NonNull CaptureRequest clientRequest,
@NonNull Executor clientExecutor,
- @NonNull ExtensionCaptureCallback clientCallbacks) {
+ @NonNull ExtensionCaptureCallback clientCallbacks,
+ @NonNull String cameraId) {
mClientRequest = clientRequest;
mClientExecutor = clientExecutor;
mClientCallbacks = clientCallbacks;
+ mCameraId = cameraId;
}
@Override
@@ -784,7 +796,7 @@
}
result.set(CaptureResult.SENSOR_TIMESTAMP, timestamp);
- TotalCaptureResult totalResult = new TotalCaptureResult(mCameraDevice.getId(), result,
+ TotalCaptureResult totalResult = new TotalCaptureResult(mCameraId, result,
mClientRequest, requestId, timestamp, new ArrayList<>(), mSessionId,
new PhysicalCaptureResultInfo[0]);
final long ident = Binder.clearCallingIdentity();
@@ -1036,14 +1048,20 @@
public int submitBurst(List<Request> requests, IRequestCallback callback) {
int seqId = -1;
try {
- CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
- ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
- for (Request request : requests) {
- captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
- mCameraConfigMap));
+ synchronized (mInterfaceLock) {
+ if (!mInitialized) {
+ return seqId;
+ }
+
+ CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
+ ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
+ for (Request request : requests) {
+ captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
+ mCameraConfigMap));
+ }
+ seqId = mCaptureSession.captureBurstRequests(captureRequests,
+ new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
}
- seqId = mCaptureSession.captureBurstRequests(captureRequests,
- new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to submit capture requests!");
} catch (IllegalStateException e) {
@@ -1057,11 +1075,17 @@
public int setRepeating(Request request, IRequestCallback callback) {
int seqId = -1;
try {
- CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
+ synchronized (mInterfaceLock) {
+ if (!mInitialized) {
+ return seqId;
+ }
+
+ CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
request, mCameraConfigMap);
- CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
- seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
- new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
+ CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
+ seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
+ new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
+ }
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to enable repeating request!");
} catch (IllegalStateException e) {
@@ -1074,7 +1098,13 @@
@Override
public void abortCaptures() {
try {
- mCaptureSession.abortCaptures();
+ synchronized (mInterfaceLock) {
+ if (!mInitialized) {
+ return;
+ }
+
+ mCaptureSession.abortCaptures();
+ }
} catch (CameraAccessException e) {
Log.e(TAG, "Failed during capture abort!");
} catch (IllegalStateException e) {
@@ -1085,7 +1115,13 @@
@Override
public void stopRepeating() {
try {
- mCaptureSession.stopRepeating();
+ synchronized (mInterfaceLock) {
+ if (!mInitialized) {
+ return;
+ }
+
+ mCaptureSession.stopRepeating();
+ }
} catch (CameraAccessException e) {
Log.e(TAG, "Failed during repeating capture stop!");
} catch (IllegalStateException e) {
diff --git a/core/java/android/service/dreams/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java
index 5469916..9a02b74b 100644
--- a/core/java/android/service/dreams/DreamOverlayService.java
+++ b/core/java/android/service/dreams/DreamOverlayService.java
@@ -71,13 +71,7 @@
@Override
public void wakeUp() {
- mService.wakeUp(this, () -> {
- try {
- mDreamOverlayCallback.onWakeUpComplete();
- } catch (RemoteException e) {
- Log.e(TAG, "Could not notify dream of wakeUp", e);
- }
- });
+ mService.wakeUp(this);
}
@Override
@@ -125,14 +119,14 @@
mCurrentClient = null;
}
- private void wakeUp(OverlayClient client, Runnable callback) {
+ private void wakeUp(OverlayClient client) {
// Run on executor as this is a binder call from OverlayClient.
mExecutor.execute(() -> {
if (mCurrentClient != client) {
return;
}
- onWakeUp(callback);
+ onWakeUp();
});
}
@@ -190,19 +184,10 @@
/**
* This method is overridden by implementations to handle when the dream has been requested
- * to wakeup. This allows any overlay animations to run. By default, the method will invoke
- * the callback immediately.
- *
- * This callback will be run on the {@link Executor} provided in the constructor if provided, or
- * on the main executor if none was provided.
- *
- * @param onCompleteCallback The callback to trigger to notify the dream service that the
- * overlay has completed waking up.
+ * to wakeup.
* @hide
*/
- public void onWakeUp(@NonNull Runnable onCompleteCallback) {
- onCompleteCallback.run();
- }
+ public void onWakeUp() {}
/**
* This method is overridden by implementations to handle when the dream has ended. There may
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 3a32352..cd57de5 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -249,13 +249,6 @@
// Simply finish dream when exit is requested.
mHandler.post(() -> finish());
}
-
- @Override
- public void onWakeUpComplete() {
- // Finish the dream once overlay animations are complete. Execute on handler since
- // this is coming in on the overlay binder.
- mHandler.post(() -> finish());
- }
};
@@ -923,6 +916,7 @@
overlay.wakeUp();
} catch (RemoteException e) {
Slog.e(TAG, "Error waking the overlay service", e);
+ } finally {
finish();
}
});
diff --git a/core/java/android/service/dreams/IDreamOverlayCallback.aidl b/core/java/android/service/dreams/IDreamOverlayCallback.aidl
index 4ad63f1..ec76a33 100644
--- a/core/java/android/service/dreams/IDreamOverlayCallback.aidl
+++ b/core/java/android/service/dreams/IDreamOverlayCallback.aidl
@@ -28,7 +28,4 @@
* Invoked to request the dream exit.
*/
void onExitRequested();
-
- /** Invoked when the dream overlay wakeUp animation is complete. */
- void onWakeUpComplete();
}
\ No newline at end of file
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 4e086c2..dbc1be1 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -44,6 +44,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.BLASTBufferQueue;
import android.graphics.Bitmap;
@@ -190,6 +191,9 @@
private Handler mBackgroundHandler;
private HandlerThread mBackgroundThread;
+ // TODO (b/287037772) remove this flag and the forceReport argument in reportVisibility
+ private boolean mIsWearOs;
+
static final class WallpaperCommand {
String action;
int x;
@@ -2282,7 +2286,8 @@
@Override
public void onDisplayChanged(int displayId) {
if (mDisplay.getDisplayId() == displayId) {
- boolean forceReport = mDisplay.getState() != Display.STATE_DOZE_SUSPEND;
+ boolean forceReport = mIsWearOs
+ && mDisplay.getState() != Display.STATE_DOZE_SUSPEND;
reportVisibility(forceReport);
}
}
@@ -2734,6 +2739,7 @@
mBackgroundThread = new HandlerThread("DefaultWallpaperLocalColorExtractor");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
+ mIsWearOs = getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
super.onCreate();
Trace.endSection();
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 5b974cd..b55d25a 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -177,7 +177,8 @@
if ((legacyWindowFlags & FLAG_FULLSCREEN) != 0) {
compatInsetsTypes &= ~statusBars();
}
- if (clearsCompatInsets(windowType, legacyWindowFlags, windowingMode)) {
+ if (clearsCompatInsets(windowType, legacyWindowFlags, windowingMode)
+ && !alwaysConsumeSystemBars) {
compatInsetsTypes = 0;
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 15f70f3..af1fdd7 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1111,8 +1111,13 @@
: controller.getSystemBarsAppearance();
if (insets != null) {
- final boolean clearsCompatInsets = clearsCompatInsets(attrs.type, attrs.flags,
- getResources().getConfiguration().windowConfiguration.getWindowingMode());
+ mLastShouldAlwaysConsumeSystemBars = insets.shouldAlwaysConsumeSystemBars();
+
+ final boolean clearsCompatInsets =
+ clearsCompatInsets(attrs.type, attrs.flags,
+ getResources().getConfiguration().windowConfiguration
+ .getWindowingMode())
+ && !mLastShouldAlwaysConsumeSystemBars;
final Insets stableBarInsets = insets.getInsetsIgnoringVisibility(
WindowInsets.Type.systemBars());
final Insets systemInsets = clearsCompatInsets
@@ -1143,7 +1148,6 @@
disallowAnimate |= (hasLeftStableInset != mLastHasLeftStableInset);
mLastHasLeftStableInset = hasLeftStableInset;
- mLastShouldAlwaysConsumeSystemBars = insets.shouldAlwaysConsumeSystemBars();
mLastSuppressScrimTypes = insets.getSuppressScrimTypes();
}
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
index b5f18c2..6ffdee1 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
@@ -45,7 +45,7 @@
@SmallTest
public void testGetEmpty() {
final Resources res = getActivity().getResources();
- assertNull(mCache.getInstance(-1, res, null).getValue());
+ assertNull(mCache.getInstance(-1, res, null));
}
@SmallTest
@@ -53,9 +53,9 @@
mCache.put(1, null, new DummyFloatConstantState(5f),
ThemedResourceCache.UNDEFINED_GENERATION);
final Resources res = getActivity().getResources();
- assertEquals(5f, mCache.getInstance(1, res, null).getValue());
- assertNotSame(5f, mCache.getInstance(1, res, null).getValue());
- assertEquals(false, mCache.getInstance(1, res, getActivity().getTheme()).hasValue());
+ assertEquals(5f, mCache.getInstance(1, res, null));
+ assertNotSame(5f, mCache.getInstance(1, res, null));
+ assertEquals(null, mCache.getInstance(1, res, getActivity().getTheme()));
}
@SmallTest
@@ -63,9 +63,9 @@
mCache.put(1, getActivity().getTheme(), new DummyFloatConstantState(5f),
ThemedResourceCache.UNDEFINED_GENERATION);
final Resources res = getActivity().getResources();
- assertEquals(false, mCache.getInstance(1, res, null).hasValue());
- assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme()).getValue());
- assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme()).getValue());
+ assertEquals(null, mCache.getInstance(1, res, null));
+ assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme()));
+ assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme()));
}
@SmallTest
@@ -75,10 +75,10 @@
mCache.put(1, null, new DummyFloatConstantState(10f),
ThemedResourceCache.UNDEFINED_GENERATION);
final Resources res = getActivity().getResources();
- assertEquals(10f, mCache.getInstance(1, res, null).getValue());
- assertNotSame(10f, mCache.getInstance(1, res, null).getValue());
- assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme()).getValue());
- assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme()).getValue());
+ assertEquals(10f, mCache.getInstance(1, res, null));
+ assertNotSame(10f, mCache.getInstance(1, res, null));
+ assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme()));
+ assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme()));
}
@SmallTest
@@ -98,9 +98,9 @@
Configuration.ORIENTATION_PORTRAIT
: Configuration.ORIENTATION_LANDSCAPE;
int changes = calcConfigChanges(res, newCnf);
- assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme()).getValue());
+ assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme()));
mCache.onConfigurationChange(changes);
- assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme()).getValue());
+ assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme()));
}
@SmallTest
@@ -123,9 +123,9 @@
: Configuration.ORIENTATION_LANDSCAPE;
int changes = calcConfigChanges(res, newCnf);
assertEquals(changingDim,
- mCache.getInstance(key, res, getActivity().getTheme()).getValue());
+ mCache.getInstance(key, res, getActivity().getTheme()));
mCache.onConfigurationChange(changes);
- assertNull(mCache.get(key, getActivity().getTheme()).getValue());
+ assertNull(mCache.get(key, getActivity().getTheme()));
}
@SmallTest
@@ -152,15 +152,15 @@
: Configuration.ORIENTATION_LANDSCAPE;
int changes = calcConfigChanges(res, newCnf);
assertEquals(staticDim, mCache.getInstance(R.dimen.resource_cache_test_generic, res,
- getActivity().getTheme()).getValue());
+ getActivity().getTheme()));
assertEquals(changingDim,
mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
- getActivity().getTheme()).getValue());
+ getActivity().getTheme()));
mCache.onConfigurationChange(changes);
assertEquals(staticDim, mCache.getInstance(R.dimen.resource_cache_test_generic, res,
- getActivity().getTheme()).getValue());
+ getActivity().getTheme()));
assertNull(mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
- getActivity().getTheme()).getValue());
+ getActivity().getTheme()));
}
@SmallTest
@@ -198,18 +198,18 @@
for (int i = 0; i < 2; i++) {
final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null;
assertEquals(staticDim,
- mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme).getValue());
+ mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme));
assertEquals(changingDim,
mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
- theme).getValue());
+ theme));
}
mCache.onConfigurationChange(changes);
for (int i = 0; i < 2; i++) {
final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null;
assertEquals(staticDim,
- mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme).getValue());
+ mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme));
assertNull(mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res,
- theme).getValue());
+ theme));
}
}
diff --git a/data/keyboards/Vendor_0957_Product_0001.kl b/data/keyboards/Vendor_0957_Product_0001.kl
index 54f8808..5d7fd85 100644
--- a/data/keyboards/Vendor_0957_Product_0001.kl
+++ b/data/keyboards/Vendor_0957_Product_0001.kl
@@ -45,6 +45,7 @@
# custom keys
key usage 0x000c01BB TV_INPUT
+key usage 0x000c0186 MACRO_1
key usage 0x000c0185 TV_TELETEXT
key usage 0x000c0061 CAPTIONS
@@ -77,4 +78,4 @@
key usage 0x000c0077 BUTTON_3 WAKE #YouTube
key usage 0x000c0078 BUTTON_4 WAKE #Netflix
key usage 0x000c0079 BUTTON_6 WAKE
-key usage 0x000c007A BUTTON_7 WAKE
\ No newline at end of file
+key usage 0x000c007A BUTTON_7 WAKE
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
index 96190c4b..1e6e503 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
@@ -28,6 +28,7 @@
import android.util.Pair;
import android.view.Display;
import android.view.DisplayAddress;
+import android.view.Surface;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -36,6 +37,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import java.util.Objects;
@@ -229,27 +231,43 @@
* @since {@link WindowExtensions#VENDOR_API_LEVEL_3}
*/
@Override
+ @NonNull
public DisplayMetrics getRearDisplayMetrics() {
- DisplayMetrics metrics = null;
+ DisplayMetrics rearDisplayMetrics = null;
// DISPLAY_CATEGORY_REAR displays are only available when you are in the concurrent
// display state, so we have to look through all displays to match the address
- Display[] displays = mDisplayManager.getDisplays(
+ final Display[] displays = mDisplayManager.getDisplays(
DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
+
+
for (int i = 0; i < displays.length; i++) {
DisplayAddress.Physical address =
(DisplayAddress.Physical) displays[i].getAddress();
if (mRearDisplayAddress == address.getPhysicalDisplayId()) {
- metrics = new DisplayMetrics();
- displays[i].getRealMetrics(metrics);
+ rearDisplayMetrics = new DisplayMetrics();
+ final Display rearDisplay = displays[i];
+
+ // We must always retrieve the metrics for the rear display regardless of if it is
+ // the default display or not.
+ rearDisplay.getRealMetrics(rearDisplayMetrics);
+
+ // TODO(b/287170025): This should be something like if (!rearDisplay.isEnabled)
+ // instead. Currently when the rear display is disabled, its state is STATE_OFF.
+ if (rearDisplay.getDisplayId() != Display.DEFAULT_DISPLAY) {
+ final Display defaultDisplay = mDisplayManager
+ .getDisplay(Display.DEFAULT_DISPLAY);
+ rotateRearDisplayMetricsIfNeeded(defaultDisplay.getRotation(),
+ rearDisplay.getRotation(), rearDisplayMetrics);
+ }
break;
}
}
synchronized (mLock) {
// Update the rear display metrics with our latest value if one was received
- if (metrics != null) {
- mRearDisplayMetrics = metrics;
+ if (rearDisplayMetrics != null) {
+ mRearDisplayMetrics = rearDisplayMetrics;
}
return Objects.requireNonNullElseGet(mRearDisplayMetrics, DisplayMetrics::new);
@@ -540,6 +558,34 @@
return mLastReportedRearDisplayPresentationStatus;
}
+ @VisibleForTesting
+ static void rotateRearDisplayMetricsIfNeeded(
+ @Surface.Rotation int defaultDisplayRotation,
+ @Surface.Rotation int rearDisplayRotation,
+ @NonNull DisplayMetrics inOutMetrics) {
+ // If the rear display has a non-zero rotation, it means the backing DisplayContent /
+ // DisplayRotation is fresh.
+ if (rearDisplayRotation != Surface.ROTATION_0) {
+ return;
+ }
+
+ // If the default display is 0 or 180, the rear display must also be 0 or 180.
+ if (defaultDisplayRotation == Surface.ROTATION_0
+ || defaultDisplayRotation == Surface.ROTATION_180) {
+ return;
+ }
+
+ final int heightPixels = inOutMetrics.heightPixels;
+ final int widthPixels = inOutMetrics.widthPixels;
+ inOutMetrics.widthPixels = heightPixels;
+ inOutMetrics.heightPixels = widthPixels;
+
+ final int noncompatHeightPixels = inOutMetrics.noncompatHeightPixels;
+ final int noncompatWidthPixels = inOutMetrics.noncompatWidthPixels;
+ inOutMetrics.noncompatWidthPixels = noncompatHeightPixels;
+ inOutMetrics.noncompatHeightPixels = noncompatWidthPixels;
+ }
+
/**
* Callback for the {@link DeviceStateRequest} to be notified of when the request has been
* activated or cancelled. This callback provides information to the client library
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/area/WindowAreaComponentImplTests.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/area/WindowAreaComponentImplTests.java
new file mode 100644
index 0000000..ccb4ebe
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/area/WindowAreaComponentImplTests.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.area;
+
+import static org.junit.Assert.assertEquals;
+
+import android.platform.test.annotations.Presubmit;
+import android.util.DisplayMetrics;
+import android.view.Surface;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WindowAreaComponentImplTests {
+
+ private final DisplayMetrics mTestDisplayMetrics = new DisplayMetrics();
+
+ @Before
+ public void setup() {
+ mTestDisplayMetrics.widthPixels = 1;
+ mTestDisplayMetrics.heightPixels = 2;
+ mTestDisplayMetrics.noncompatWidthPixels = 3;
+ mTestDisplayMetrics.noncompatHeightPixels = 4;
+ }
+
+ /**
+ * Cases where the rear display metrics does not need to be transformed.
+ */
+ @Test
+ public void testRotateRearDisplayMetrics_noTransformNeeded() {
+ final DisplayMetrics originalMetrics = new DisplayMetrics();
+ originalMetrics.setTo(mTestDisplayMetrics);
+
+ WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+ Surface.ROTATION_0, Surface.ROTATION_0, mTestDisplayMetrics);
+ assertEquals(originalMetrics, mTestDisplayMetrics);
+
+ WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+ Surface.ROTATION_180, Surface.ROTATION_180, mTestDisplayMetrics);
+ assertEquals(originalMetrics, mTestDisplayMetrics);
+
+ WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+ Surface.ROTATION_0, Surface.ROTATION_180, mTestDisplayMetrics);
+ assertEquals(originalMetrics, mTestDisplayMetrics);
+
+ WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+ Surface.ROTATION_180, Surface.ROTATION_0, mTestDisplayMetrics);
+ assertEquals(originalMetrics, mTestDisplayMetrics);
+ }
+
+ /**
+ * Cases where the rear display metrics need to be transformed.
+ */
+ @Test
+ public void testRotateRearDisplayMetrics_transformNeeded() {
+ DisplayMetrics originalMetrics = new DisplayMetrics();
+ originalMetrics.setTo(mTestDisplayMetrics);
+
+ DisplayMetrics expectedMetrics = new DisplayMetrics();
+ expectedMetrics.setTo(mTestDisplayMetrics);
+ expectedMetrics.widthPixels = mTestDisplayMetrics.heightPixels;
+ expectedMetrics.heightPixels = mTestDisplayMetrics.widthPixels;
+ expectedMetrics.noncompatWidthPixels = mTestDisplayMetrics.noncompatHeightPixels;
+ expectedMetrics.noncompatHeightPixels = mTestDisplayMetrics.noncompatWidthPixels;
+
+ WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+ Surface.ROTATION_90, Surface.ROTATION_0, mTestDisplayMetrics);
+ assertEquals(expectedMetrics, mTestDisplayMetrics);
+
+ mTestDisplayMetrics.setTo(originalMetrics);
+ WindowAreaComponentImpl.rotateRearDisplayMetricsIfNeeded(
+ Surface.ROTATION_270, Surface.ROTATION_0, mTestDisplayMetrics);
+ assertEquals(expectedMetrics, mTestDisplayMetrics);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 4980e49..cff3172 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -61,7 +61,6 @@
import com.android.wm.shell.freeform.FreeformTaskTransitionHandler;
import com.android.wm.shell.freeform.FreeformTaskTransitionObserver;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
-import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
@@ -536,9 +535,11 @@
Optional<PipTouchHandler> pipTouchHandlerOptional,
Optional<RecentsTransitionHandler> recentsTransitionHandler,
KeyguardTransitionHandler keyguardTransitionHandler,
+ Optional<UnfoldTransitionHandler> unfoldHandler,
Transitions transitions) {
return new DefaultMixedHandler(shellInit, transitions, splitScreenOptional,
- pipTouchHandlerOptional, recentsTransitionHandler, keyguardTransitionHandler);
+ pipTouchHandlerOptional, recentsTransitionHandler, keyguardTransitionHandler,
+ unfoldHandler);
}
@WMSingleton
@@ -711,28 +712,6 @@
}
//
- // Kids mode
- //
- @WMSingleton
- @Provides
- static KidsModeTaskOrganizer provideKidsModeTaskOrganizer(
- Context context,
- ShellInit shellInit,
- ShellCommandHandler shellCommandHandler,
- SyncTransactionQueue syncTransactionQueue,
- DisplayController displayController,
- DisplayInsetsController displayInsetsController,
- Optional<UnfoldAnimationController> unfoldAnimationController,
- Optional<RecentTasksController> recentTasksOptional,
- @ShellMainThread ShellExecutor mainExecutor,
- @ShellMainThread Handler mainHandler
- ) {
- return new KidsModeTaskOrganizer(context, shellInit, shellCommandHandler,
- syncTransactionQueue, displayController, displayInsetsController,
- unfoldAnimationController, recentTasksOptional, mainExecutor, mainHandler);
- }
-
- //
// Misc
//
@@ -743,7 +722,6 @@
@Provides
static Object provideIndependentShellComponentsToCreate(
DefaultMixedHandler defaultMixedHandler,
- KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<DesktopModeController> desktopModeController) {
return new Object();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java
deleted file mode 100644
index 65cb7ac..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.kidsmode;
-
-import android.annotation.NonNull;
-import android.app.ActivityManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-
-import java.util.Collection;
-
-/**
- * A ContentObserver for listening kids mode relative setting keys:
- * - {@link Settings.Secure#NAVIGATION_MODE}
- * - {@link Settings.Secure#NAV_BAR_KIDS_MODE}
- *
- * @hide
- */
-public class KidsModeSettingsObserver extends ContentObserver {
- private Context mContext;
- private Runnable mOnChangeRunnable;
-
- public KidsModeSettingsObserver(Handler handler, Context context) {
- super(handler);
- mContext = context;
- }
-
- public void setOnChangeRunnable(Runnable r) {
- mOnChangeRunnable = r;
- }
-
- /**
- * Registers the observer.
- */
- public void register() {
- final ContentResolver r = mContext.getContentResolver();
- r.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.NAVIGATION_MODE),
- false, this, UserHandle.USER_ALL);
- r.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE),
- false, this, UserHandle.USER_ALL);
- }
-
- /**
- * Unregisters the observer.
- */
- public void unregister() {
- mContext.getContentResolver().unregisterContentObserver(this);
- }
-
- @Override
- public void onChange(boolean selfChange, @NonNull Collection<Uri> uris, int flags, int userId) {
- if (userId != ActivityManager.getCurrentUser()) {
- return;
- }
-
- if (mOnChangeRunnable != null) {
- mOnChangeRunnable.run();
- }
- }
-
- /**
- * Returns true only when it's in three button nav mode and the kid nav bar mode is enabled.
- * Otherwise, return false.
- */
- public boolean isEnabled() {
- return Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.NAVIGATION_MODE, 0, UserHandle.USER_CURRENT) == 0
- && Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.NAV_BAR_KIDS_MODE, 0, UserHandle.USER_CURRENT) == 1;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
deleted file mode 100644
index 6d46a9c..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.kidsmode;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.view.Display;
-import android.view.InsetsSource;
-import android.view.InsetsState;
-import android.view.SurfaceControl;
-import android.view.WindowInsets;
-import android.window.ITaskOrganizerController;
-import android.window.TaskAppearedInfo;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.recents.RecentTasksController;
-import com.android.wm.shell.sysui.ShellCommandHandler;
-import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.unfold.UnfoldAnimationController;
-
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.Optional;
-
-/**
- * A dedicated task organizer when kids mode is enabled.
- * - Creates a root task with bounds that exclude the navigation bar area
- * - Launch all task into the root task except for Launcher
- */
-public class KidsModeTaskOrganizer extends ShellTaskOrganizer {
- private static final String TAG = "KidsModeTaskOrganizer";
-
- private static final int[] CONTROLLED_ACTIVITY_TYPES =
- {ACTIVITY_TYPE_UNDEFINED, ACTIVITY_TYPE_STANDARD, ACTIVITY_TYPE_HOME};
- private static final int[] CONTROLLED_WINDOWING_MODES =
- {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED};
-
- private final Handler mMainHandler;
- private final Context mContext;
- private final ShellCommandHandler mShellCommandHandler;
- private final SyncTransactionQueue mSyncQueue;
- private final DisplayController mDisplayController;
- private final DisplayInsetsController mDisplayInsetsController;
-
- /**
- * The value of the {@link R.bool.config_reverseDefaultRotation} property which defines how
- * {@link Display#getRotation} values are mapped to screen orientations
- */
- private final boolean mReverseDefaultRotationEnabled;
-
- @VisibleForTesting
- ActivityManager.RunningTaskInfo mLaunchRootTask;
- @VisibleForTesting
- SurfaceControl mLaunchRootLeash;
- @VisibleForTesting
- final IBinder mCookie = new Binder();
-
- private final InsetsState mInsetsState = new InsetsState();
- private int mDisplayWidth;
- private int mDisplayHeight;
-
- private KidsModeSettingsObserver mKidsModeSettingsObserver;
- private boolean mEnabled;
-
- private ActivityManager.RunningTaskInfo mHomeTask;
-
- private final BroadcastReceiver mUserSwitchIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- updateKidsModeState();
- }
- };
-
- DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener =
- new DisplayController.OnDisplaysChangedListener() {
- @Override
- public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
- final DisplayLayout displayLayout =
- mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
- if (displayLayout == null) {
- return;
- }
- final int displayWidth = displayLayout.width();
- final int displayHeight = displayLayout.height();
- if (displayWidth == mDisplayWidth || displayHeight == mDisplayHeight) {
- return;
- }
- mDisplayWidth = displayWidth;
- mDisplayHeight = displayHeight;
- updateBounds();
- }
- };
-
- DisplayInsetsController.OnInsetsChangedListener mOnInsetsChangedListener =
- new DisplayInsetsController.OnInsetsChangedListener() {
- @Override
- public void insetsChanged(InsetsState insetsState) {
- final boolean[] navigationBarChanged = {false};
- InsetsState.traverse(insetsState, mInsetsState, new InsetsState.OnTraverseCallbacks() {
- @Override
- public void onIdMatch(InsetsSource source1, InsetsSource source2) {
- if (source1.getType() == WindowInsets.Type.navigationBars()
- && !source1.equals(source2)) {
- navigationBarChanged[0] = true;
- }
- }
-
- @Override
- public void onIdNotFoundInState1(int index2, InsetsSource source2) {
- if (source2.getType() == WindowInsets.Type.navigationBars()) {
- navigationBarChanged[0] = true;
- }
- }
-
- @Override
- public void onIdNotFoundInState2(int index1, InsetsSource source1) {
- if (source1.getType() == WindowInsets.Type.navigationBars()) {
- navigationBarChanged[0] = true;
- }
- }
- });
- if (!navigationBarChanged[0]) {
- return;
- }
- // Update bounds only when the insets of navigation bar or task bar is changed.
- mInsetsState.set(insetsState);
- updateBounds();
- }
- };
-
- @VisibleForTesting
- KidsModeTaskOrganizer(
- Context context,
- ShellInit shellInit,
- ShellCommandHandler shellCommandHandler,
- ITaskOrganizerController taskOrganizerController,
- SyncTransactionQueue syncTransactionQueue,
- DisplayController displayController,
- DisplayInsetsController displayInsetsController,
- Optional<UnfoldAnimationController> unfoldAnimationController,
- Optional<RecentTasksController> recentTasks,
- KidsModeSettingsObserver kidsModeSettingsObserver,
- ShellExecutor mainExecutor,
- Handler mainHandler) {
- // Note: we don't call super with the shell init because we will be initializing manually
- super(/* shellInit= */ null, /* shellCommandHandler= */ null, taskOrganizerController,
- /* compatUI= */ null, unfoldAnimationController, recentTasks, mainExecutor);
- mContext = context;
- mShellCommandHandler = shellCommandHandler;
- mMainHandler = mainHandler;
- mSyncQueue = syncTransactionQueue;
- mDisplayController = displayController;
- mDisplayInsetsController = displayInsetsController;
- mKidsModeSettingsObserver = kidsModeSettingsObserver;
- shellInit.addInitCallback(this::onInit, this);
- mReverseDefaultRotationEnabled = context.getResources().getBoolean(
- R.bool.config_reverseDefaultRotation);
- }
-
- public KidsModeTaskOrganizer(
- Context context,
- ShellInit shellInit,
- ShellCommandHandler shellCommandHandler,
- SyncTransactionQueue syncTransactionQueue,
- DisplayController displayController,
- DisplayInsetsController displayInsetsController,
- Optional<UnfoldAnimationController> unfoldAnimationController,
- Optional<RecentTasksController> recentTasks,
- ShellExecutor mainExecutor,
- Handler mainHandler) {
- // Note: we don't call super with the shell init because we will be initializing manually
- super(/* shellInit= */ null, /* taskOrganizerController= */ null, /* compatUI= */ null,
- unfoldAnimationController, recentTasks, mainExecutor);
- mContext = context;
- mShellCommandHandler = shellCommandHandler;
- mMainHandler = mainHandler;
- mSyncQueue = syncTransactionQueue;
- mDisplayController = displayController;
- mDisplayInsetsController = displayInsetsController;
- shellInit.addInitCallback(this::onInit, this);
- mReverseDefaultRotationEnabled = context.getResources().getBoolean(
- R.bool.config_reverseDefaultRotation);
- }
-
- /**
- * Initializes kids mode status.
- */
- public void onInit() {
- if (mShellCommandHandler != null) {
- mShellCommandHandler.addDumpCallback(this::dump, this);
- }
- if (mKidsModeSettingsObserver == null) {
- mKidsModeSettingsObserver = new KidsModeSettingsObserver(mMainHandler, mContext);
- }
- mKidsModeSettingsObserver.setOnChangeRunnable(() -> updateKidsModeState());
- updateKidsModeState();
- mKidsModeSettingsObserver.register();
-
- final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- mContext.registerReceiverForAllUsers(mUserSwitchIntentReceiver, filter, null, mMainHandler);
- }
-
- @Override
- public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- if (mEnabled && mLaunchRootTask == null && taskInfo.launchCookies != null
- && taskInfo.launchCookies.contains(mCookie)) {
- mLaunchRootTask = taskInfo;
- mLaunchRootLeash = leash;
- updateTask();
- }
- super.onTaskAppeared(taskInfo, leash);
-
- // Only allow home to draw under system bars.
- if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME) {
- final WindowContainerTransaction wct = getWindowContainerTransaction();
- wct.setBounds(taskInfo.token, new Rect(0, 0, mDisplayWidth, mDisplayHeight));
- mSyncQueue.queue(wct);
- mHomeTask = taskInfo;
- }
- mSyncQueue.runInSync(t -> {
- // Reset several properties back to fullscreen (PiP, for example, leaves all these
- // properties in a bad state).
- t.setCrop(leash, null);
- t.setPosition(leash, 0, 0);
- t.setAlpha(leash, 1f);
- t.setMatrix(leash, 1, 0, 0, 1);
- t.show(leash);
- });
- }
-
- @Override
- public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
- if (mLaunchRootTask != null && mLaunchRootTask.taskId == taskInfo.taskId
- && !taskInfo.equals(mLaunchRootTask)) {
- mLaunchRootTask = taskInfo;
- }
-
- if (mHomeTask != null && mHomeTask.taskId == taskInfo.taskId
- && !taskInfo.equals(mHomeTask)) {
- mHomeTask = taskInfo;
- }
-
- super.onTaskInfoChanged(taskInfo);
- }
-
- @VisibleForTesting
- void updateKidsModeState() {
- final boolean enabled = mKidsModeSettingsObserver.isEnabled();
- if (mEnabled == enabled) {
- return;
- }
- mEnabled = enabled;
- if (mEnabled) {
- enable();
- } else {
- disable();
- }
- }
-
- @VisibleForTesting
- void enable() {
- // Needed since many Kids apps aren't optimised to support both orientations and it will be
- // hard for kids to understand the app compat mode.
- // TODO(229961548): Remove ignoreOrientationRequest exception for Kids Mode once possible.
- if (mReverseDefaultRotationEnabled) {
- setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ true,
- /* fromOrientations */
- new int[]{SCREEN_ORIENTATION_LANDSCAPE, SCREEN_ORIENTATION_REVERSE_LANDSCAPE},
- /* toOrientations */
- new int[]{SCREEN_ORIENTATION_SENSOR_LANDSCAPE,
- SCREEN_ORIENTATION_SENSOR_LANDSCAPE});
- } else {
- setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ true,
- /* fromOrientations */ null, /* toOrientations */ null);
- }
- final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
- if (displayLayout != null) {
- mDisplayWidth = displayLayout.width();
- mDisplayHeight = displayLayout.height();
- }
- mInsetsState.set(mDisplayController.getInsetsState(DEFAULT_DISPLAY));
- mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY,
- mOnInsetsChangedListener);
- mDisplayController.addDisplayWindowListener(mOnDisplaysChangedListener);
- List<TaskAppearedInfo> taskAppearedInfos = registerOrganizer();
- for (int i = 0; i < taskAppearedInfos.size(); i++) {
- final TaskAppearedInfo info = taskAppearedInfos.get(i);
- onTaskAppeared(info.getTaskInfo(), info.getLeash());
- }
- createRootTask(DEFAULT_DISPLAY, WINDOWING_MODE_FULLSCREEN, mCookie);
- updateTask();
- }
-
- @VisibleForTesting
- void disable() {
- setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ false,
- /* fromOrientations */ null, /* toOrientations */ null);
- mDisplayInsetsController.removeInsetsChangedListener(DEFAULT_DISPLAY,
- mOnInsetsChangedListener);
- mDisplayController.removeDisplayWindowListener(mOnDisplaysChangedListener);
- updateTask();
- final WindowContainerToken token = mLaunchRootTask.token;
- if (token != null) {
- deleteRootTask(token);
- }
- mLaunchRootTask = null;
- mLaunchRootLeash = null;
- if (mHomeTask != null && mHomeTask.token != null) {
- final WindowContainerToken homeToken = mHomeTask.token;
- final WindowContainerTransaction wct = getWindowContainerTransaction();
- wct.setBounds(homeToken, null);
- mSyncQueue.queue(wct);
- }
- mHomeTask = null;
- unregisterOrganizer();
- }
-
- private void updateTask() {
- updateTask(getWindowContainerTransaction());
- }
-
- private void updateTask(WindowContainerTransaction wct) {
- if (mLaunchRootTask == null || mLaunchRootLeash == null) {
- return;
- }
- final Rect taskBounds = calculateBounds();
- final WindowContainerToken rootToken = mLaunchRootTask.token;
- wct.setBounds(rootToken, mEnabled ? taskBounds : null);
- wct.setLaunchRoot(rootToken,
- mEnabled ? CONTROLLED_WINDOWING_MODES : null,
- mEnabled ? CONTROLLED_ACTIVITY_TYPES : null);
- wct.reparentTasks(
- mEnabled ? null : rootToken /* currentParent */,
- mEnabled ? rootToken : null /* newParent */,
- CONTROLLED_WINDOWING_MODES,
- CONTROLLED_ACTIVITY_TYPES,
- true /* onTop */);
- wct.reorder(rootToken, mEnabled /* onTop */);
- mSyncQueue.queue(wct);
- if (mEnabled) {
- final SurfaceControl rootLeash = mLaunchRootLeash;
- mSyncQueue.runInSync(t -> {
- t.setPosition(rootLeash, taskBounds.left, taskBounds.top);
- t.setWindowCrop(rootLeash, mDisplayWidth, mDisplayHeight);
- });
- }
- }
-
- private Rect calculateBounds() {
- final Rect bounds = new Rect(0, 0, mDisplayWidth, mDisplayHeight);
- bounds.inset(mInsetsState.calculateInsets(
- bounds, WindowInsets.Type.navigationBars(), false /* ignoreVisibility */));
- return bounds;
- }
-
- private void updateBounds() {
- if (mLaunchRootTask == null) {
- return;
- }
- final WindowContainerTransaction wct = getWindowContainerTransaction();
- final Rect taskBounds = calculateBounds();
- wct.setBounds(mLaunchRootTask.token, taskBounds);
- wct.setBounds(mHomeTask.token, new Rect(0, 0, mDisplayWidth, mDisplayHeight));
- mSyncQueue.queue(wct);
- final SurfaceControl finalLeash = mLaunchRootLeash;
- mSyncQueue.runInSync(t -> {
- t.setPosition(finalLeash, taskBounds.left, taskBounds.top);
- t.setWindowCrop(finalLeash, mDisplayWidth, mDisplayHeight);
- });
- }
-
- @VisibleForTesting
- WindowContainerTransaction getWindowContainerTransaction() {
- return new WindowContainerTransaction();
- }
-
- @Override
- public void dump(@NonNull PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- pw.println(prefix + TAG);
- pw.println(innerPrefix + " mEnabled=" + mEnabled);
- pw.println(innerPrefix + " mLaunchRootTask=" + mLaunchRootTask);
- pw.println(innerPrefix + " mLaunchRootLeash=" + mLaunchRootLeash);
- pw.println(innerPrefix + " mDisplayWidth=" + mDisplayWidth);
- pw.println(innerPrefix + " mDisplayHeight=" + mDisplayHeight);
- pw.println(innerPrefix + " mInsetsState=" + mInsetsState);
- super.dump(pw, innerPrefix);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 8024a4c..843e5af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -424,6 +424,7 @@
// the change count). This lets us categorize things into above/below/between
// while maintaining their relative ordering.
final int belowLayers = info.getChanges().size();
+ final int middleLayers = info.getChanges().size() * 2;
final int aboveLayers = info.getChanges().size() * 3;
for (int i = 0; i < info.getChanges().size(); ++i) {
final TransitionInfo.Change change = info.getChanges().get(i);
@@ -441,14 +442,19 @@
belowLayers - i, info, t, mLeashMap);
apps.add(target);
if (TransitionUtil.isClosingType(change.getMode())) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
- " adding pausing leaf taskId=%d", taskInfo.taskId);
- // raise closing (pausing) task to "above" layer so it isn't covered
- t.setLayer(target.leash, aboveLayers - i);
mPausingTasks.add(new TaskState(change, target.leash));
if (taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ " adding pausing leaf home taskId=%d", taskInfo.taskId);
// This can only happen if we have a separate recents/home (3p launcher)
mPausingSeparateHome = true;
+ } else {
+ final int layer = aboveLayers - i;
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ " adding pausing leaf taskId=%d at layer=%d",
+ taskInfo.taskId, layer);
+ // raise closing (pausing) task to "above" layer so it isn't covered
+ t.setLayer(target.leash, layer);
}
if (taskInfo.pictureInPictureParams != null
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
@@ -456,8 +462,12 @@
}
} else if (taskInfo != null
&& taskInfo.topActivityType == ACTIVITY_TYPE_RECENTS) {
- // There's a 3p launcher, so make sure recents goes above that.
- t.setLayer(target.leash, aboveLayers - i);
+ final int layer = middleLayers - i;
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ " setting recents activity layer=%d", layer);
+ // There's a 3p launcher, so make sure recents goes above that, but under
+ // the pausing apps.
+ t.setLayer(target.leash, layer);
} else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
// do nothing
} else if (TransitionUtil.isOpeningType(change.getMode())) {
@@ -468,16 +478,18 @@
} else if (taskInfo != null && TransitionInfo.isIndependent(change, info)) {
// Root tasks
if (TransitionUtil.isClosingType(change.getMode())) {
+ final int layer = aboveLayers - i;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
- " adding pausing taskId=%d", taskInfo.taskId);
+ " adding pausing taskId=%d at layer=%d", taskInfo.taskId, layer);
// raise closing (pausing) task to "above" layer so it isn't covered
- t.setLayer(change.getLeash(), aboveLayers - i);
+ t.setLayer(change.getLeash(), layer);
mPausingTasks.add(new TaskState(change, null /* leash */));
} else if (TransitionUtil.isOpeningType(change.getMode())) {
+ final int layer = belowLayers - i;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
- " adding opening taskId=%d", taskInfo.taskId);
+ " adding opening taskId=%d at layer=%d", taskInfo.taskId, layer);
// Put into the "below" layer space.
- t.setLayer(change.getLeash(), belowLayers - i);
+ t.setLayer(change.getLeash(), layer);
mOpeningTasks.add(new TaskState(change, null /* leash */));
}
} else if (TransitionUtil.isDividerBar(change)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index da14d03..d38c381 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -2365,6 +2365,11 @@
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
}
}
+
+ // When split in the background, it should be only opening/dismissing transition and
+ // would keep out not empty. Prevent intercepting all transitions for split screen when
+ // it is in the background and not identify to handle it.
+ return (!out.isEmpty() || isSplitScreenVisible()) ? out : null;
} else {
if (isOpening && getStageOfTask(triggerTask) != null) {
// One task is appearing into split, prepare to enter split screen.
@@ -2373,8 +2378,8 @@
mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
TRANSIT_SPLIT_SCREEN_PAIR_OPEN, !mIsDropEntering);
}
+ return out;
}
- return out;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 18c5a2a..3059e85 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -51,6 +51,7 @@
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.splitscreen.StageCoordinator;
import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.unfold.UnfoldTransitionHandler;
import com.android.wm.shell.util.TransitionUtil;
import java.util.ArrayList;
@@ -68,6 +69,7 @@
private RecentsTransitionHandler mRecentsHandler;
private StageCoordinator mSplitHandler;
private final KeyguardTransitionHandler mKeyguardHandler;
+ private UnfoldTransitionHandler mUnfoldHandler;
private static class MixedTransition {
static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;
@@ -84,6 +86,9 @@
/** Keyguard exit/occlude/unocclude transition. */
static final int TYPE_KEYGUARD = 5;
+ /** Fuld/Unfold transition. */
+ static final int TYPE_UNFOLD = 6;
+
/** The default animation for this mixed transition. */
static final int ANIM_TYPE_DEFAULT = 0;
@@ -135,7 +140,8 @@
Optional<SplitScreenController> splitScreenControllerOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
Optional<RecentsTransitionHandler> recentsHandlerOptional,
- KeyguardTransitionHandler keyguardHandler) {
+ KeyguardTransitionHandler keyguardHandler,
+ Optional<UnfoldTransitionHandler> unfoldHandler) {
mPlayer = player;
mKeyguardHandler = keyguardHandler;
if (Transitions.ENABLE_SHELL_TRANSITIONS && pipTouchHandlerOptional.isPresent()
@@ -152,6 +158,7 @@
if (mRecentsHandler != null) {
mRecentsHandler.addMixer(this);
}
+ mUnfoldHandler = unfoldHandler.orElse(null);
}, this);
}
}
@@ -215,6 +222,16 @@
mixed.mLeftoversHandler = handler.first;
mActiveTransitions.add(mixed);
return handler.second;
+ } else if (mUnfoldHandler != null && mUnfoldHandler.hasUnfold(request)) {
+ final WindowContainerTransaction wct =
+ mUnfoldHandler.handleRequest(transition, request);
+ if (wct != null) {
+ final MixedTransition mixed = new MixedTransition(
+ MixedTransition.TYPE_UNFOLD, transition);
+ mixed.mLeftoversHandler = mUnfoldHandler;
+ mActiveTransitions.add(mixed);
+ }
+ return wct;
}
return null;
}
@@ -322,6 +339,8 @@
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
return animateKeyguard(mixed, info, startTransaction, finishTransaction,
finishCallback);
+ } else if (mixed.mType == MixedTransition.TYPE_UNFOLD) {
+ return animateUnfold(mixed, info, startTransaction, finishTransaction, finishCallback);
} else {
mActiveTransitions.remove(mixed);
throw new IllegalStateException("Starting mixed animation without a known mixed type? "
@@ -606,6 +625,33 @@
return true;
}
+ private boolean animateUnfold(@NonNull final MixedTransition mixed,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ final Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ mixed.mInFlightSubAnimations--;
+ if (mixed.mInFlightSubAnimations > 0) return;
+ mActiveTransitions.remove(mixed);
+ finishCallback.onTransitionFinished(wct, wctCB);
+ };
+ mixed.mInFlightSubAnimations = 1;
+ if (!mUnfoldHandler.startAnimation(
+ mixed.mTransition, info, startTransaction, finishTransaction, finishCB)) {
+ return false;
+ }
+ // Sync pip state.
+ if (mPipHandler != null) {
+ // We don't know when to apply `startTransaction` so use a separate transaction here.
+ // This should be fine because these surface properties are independent.
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ mPipHandler.syncPipSurfaceState(info, t, finishTransaction);
+ t.apply();
+ }
+ return true;
+ }
+
/** Use to when split use intent to enter, check if this enter transition should be mixed or
* not.*/
public boolean shouldSplitEnterMixed(PendingIntent intent) {
@@ -665,6 +711,8 @@
finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
mKeyguardHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
+ } else if (mixed.mType == MixedTransition.TYPE_UNFOLD) {
+ mUnfoldHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
} else {
throw new IllegalStateException("Playing a mixed transition with unknown type? "
+ mixed.mType);
@@ -690,6 +738,8 @@
mixed.mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT);
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
mKeyguardHandler.onTransitionConsumed(transition, aborted, finishT);
+ } else if (mixed.mType == MixedTransition.TYPE_UNFOLD) {
+ mUnfoldHandler.onTransitionConsumed(transition, aborted, finishT);
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index e1d58a4..f148412 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -197,12 +197,18 @@
}
}
+ /** Whether `request` contains an unfold action. */
+ public boolean hasUnfold(@NonNull TransitionRequestInfo request) {
+ return (request.getType() == TRANSIT_CHANGE
+ && request.getDisplayChange() != null
+ && request.getDisplayChange().isPhysicalDisplayChanged());
+ }
+
@Nullable
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request) {
- if (request.getType() == TRANSIT_CHANGE && request.getDisplayChange() != null
- && request.getDisplayChange().isPhysicalDisplayChanged()) {
+ if (hasUnfold(request)) {
mTransition = transition;
return new WindowContainerTransaction();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
deleted file mode 100644
index 58e91cb..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.kidsmode;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.pm.ParceledListSlice;
-import android.content.res.Resources;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.view.InsetsState;
-import android.view.SurfaceControl;
-import android.window.ITaskOrganizerController;
-import android.window.TaskAppearedInfo;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayInsetsController;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.sysui.ShellCommandHandler;
-import com.android.wm.shell.sysui.ShellInit;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.Optional;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class KidsModeTaskOrganizerTest extends ShellTestCase {
- @Mock private ITaskOrganizerController mTaskOrganizerController;
- @Mock private Context mContext;
- @Mock private Handler mHandler;
- @Mock private SyncTransactionQueue mSyncTransactionQueue;
- @Mock private ShellExecutor mTestExecutor;
- @Mock private DisplayController mDisplayController;
- @Mock private SurfaceControl mLeash;
- @Mock private WindowContainerToken mToken;
- @Mock private WindowContainerTransaction mTransaction;
- @Mock private KidsModeSettingsObserver mObserver;
- @Mock private ShellInit mShellInit;
- @Mock private ShellCommandHandler mShellCommandHandler;
- @Mock private DisplayInsetsController mDisplayInsetsController;
- @Mock private Resources mResources;
-
- KidsModeTaskOrganizer mOrganizer;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- try {
- doReturn(ParceledListSlice.<TaskAppearedInfo>emptyList())
- .when(mTaskOrganizerController).registerTaskOrganizer(any());
- } catch (RemoteException e) {
- }
- // NOTE: KidsModeTaskOrganizer should have a null CompatUIController.
- doReturn(mResources).when(mContext).getResources();
- final KidsModeTaskOrganizer kidsModeTaskOrganizer = new KidsModeTaskOrganizer(mContext,
- mShellInit, mShellCommandHandler, mTaskOrganizerController, mSyncTransactionQueue,
- mDisplayController, mDisplayInsetsController, Optional.empty(), Optional.empty(),
- mObserver, mTestExecutor, mHandler);
- mOrganizer = spy(kidsModeTaskOrganizer);
- doReturn(mTransaction).when(mOrganizer).getWindowContainerTransaction();
- doReturn(new InsetsState()).when(mDisplayController).getInsetsState(DEFAULT_DISPLAY);
- }
-
- @Test
- public void instantiateController_addInitCallback() {
- verify(mShellInit, times(1)).addInitCallback(any(), any());
- }
-
- @Test
- public void testKidsModeOn() {
- doReturn(true).when(mObserver).isEnabled();
-
- mOrganizer.updateKidsModeState();
-
- verify(mOrganizer, times(1)).enable();
- verify(mOrganizer, times(1)).registerOrganizer();
- verify(mOrganizer, times(1)).createRootTask(
- eq(DEFAULT_DISPLAY), eq(WINDOWING_MODE_FULLSCREEN), eq(mOrganizer.mCookie));
- verify(mOrganizer, times(1))
- .setOrientationRequestPolicy(eq(true), any(), any());
-
- final ActivityManager.RunningTaskInfo rootTask = createTaskInfo(12,
- WINDOWING_MODE_FULLSCREEN, mOrganizer.mCookie);
- mOrganizer.onTaskAppeared(rootTask, mLeash);
-
- assertThat(mOrganizer.mLaunchRootLeash).isEqualTo(mLeash);
- assertThat(mOrganizer.mLaunchRootTask).isEqualTo(rootTask);
- }
-
- @Test
- public void testKidsModeOff() {
- doReturn(true).when(mObserver).isEnabled();
- mOrganizer.updateKidsModeState();
- final ActivityManager.RunningTaskInfo rootTask = createTaskInfo(12,
- WINDOWING_MODE_FULLSCREEN, mOrganizer.mCookie);
- mOrganizer.onTaskAppeared(rootTask, mLeash);
-
- doReturn(false).when(mObserver).isEnabled();
- mOrganizer.updateKidsModeState();
-
- verify(mOrganizer, times(1)).disable();
- verify(mOrganizer, times(1)).unregisterOrganizer();
- verify(mOrganizer, times(1)).deleteRootTask(rootTask.token);
- verify(mOrganizer, times(1))
- .setOrientationRequestPolicy(eq(false), any(), any());
- assertThat(mOrganizer.mLaunchRootLeash).isNull();
- assertThat(mOrganizer.mLaunchRootTask).isNull();
- }
-
- private ActivityManager.RunningTaskInfo createTaskInfo(
- int taskId, int windowingMode, IBinder cookies) {
- ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
- taskInfo.taskId = taskId;
- taskInfo.token = mToken;
- taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
- final ArrayList<IBinder> launchCookies = new ArrayList<>();
- if (cookies != null) {
- launchCookies.add(cookies);
- }
- taskInfo.launchCookies = launchCookies;
- return taskInfo;
- }
-}
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 9be7728..0eb657a 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -709,7 +709,7 @@
/**
* Returns the Mean Sea Level altitude of this location in meters.
*
- * <p>This is only valid if {@link #hasMslAltitude()} is true.
+ * @throws IllegalStateException if {@link #hasMslAltitude()} is false.
*/
public @FloatRange double getMslAltitudeMeters() {
Preconditions.checkState(hasMslAltitude(),
@@ -744,7 +744,7 @@
* percentile confidence level. This means that there is 68% chance that the true Mean Sea Level
* altitude of this location falls within {@link #getMslAltitudeMeters()} +/- this uncertainty.
*
- * <p>This is only valid if {@link #hasMslAltitudeAccuracy()} is true.
+ * @throws IllegalStateException if {@link #hasMslAltitudeAccuracy()} is false.
*/
public @FloatRange(from = 0.0) float getMslAltitudeAccuracyMeters() {
Preconditions.checkState(hasMslAltitudeAccuracy(),
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index f277e8a..da4547b 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -76,4 +76,10 @@
<!-- Bouncer user switcher margins -->
<dimen name="bouncer_user_switcher_view_mode_user_switcher_bottom_margin">0dp</dimen>
<dimen name="bouncer_user_switcher_view_mode_view_flipper_bottom_margin">0dp</dimen>
+
+ <!-- Power Menu Lite -->
+ <!-- These values are for small screen landscape. For larger landscape screens, they are
+ overlaid -->
+ <dimen name="global_actions_button_size">72dp</dimen>
+ <dimen name="global_actions_button_padding">26dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw410dp-land/dimens.xml b/packages/SystemUI/res/values-sw410dp-land/dimens.xml
index c4d9b9b..6045606 100644
--- a/packages/SystemUI/res/values-sw410dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw410dp-land/dimens.xml
@@ -18,4 +18,8 @@
<!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
<dimen name="biometric_auth_pattern_view_size">248dp</dimen>
<dimen name="biometric_auth_pattern_view_max_size">348dp</dimen>
+
+ <!-- Power Menu Lite -->
+ <dimen name="global_actions_button_size">96dp</dimen>
+ <dimen name="global_actions_button_padding">38dp</dimen>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
index a724514..b52ee01 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
@@ -148,7 +148,8 @@
/**
* The status of this lock screen. Primarily used for widgets on LockScreen.
*/
- private enum StatusMode {
+ @VisibleForTesting
+ protected enum StatusMode {
Normal, // Normal case (sim card present, it's not locked)
NetworkLocked, // SIM card is 'network locked'.
SimMissing, // SIM card is missing.
@@ -158,6 +159,7 @@
SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure
SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM.
SimIoError, // SIM card is faulty
+ SimRestricted, // SIM Card restricted, present but not usable due to carrier restrictions.
SimUnknown // SIM card is unknown
}
@@ -493,6 +495,7 @@
getContext().getText(R.string.keyguard_sim_error_message_short),
text);
break;
+ case SimRestricted: // fall through
case SimUnknown:
carrierText = null;
break;
@@ -535,19 +538,19 @@
/**
* Determine the current status of the lock screen given the SIM state and other stuff.
*/
- private CarrierTextManager.StatusMode getStatusForIccState(int simState) {
- final boolean missingAndNotProvisioned =
- !mKeyguardUpdateMonitor.isDeviceProvisioned()
- && (simState == TelephonyManager.SIM_STATE_ABSENT
- || simState == TelephonyManager.SIM_STATE_PERM_DISABLED);
+ @VisibleForTesting
+ protected CarrierTextManager.StatusMode getStatusForIccState(int simState) {
+ if (!mKeyguardUpdateMonitor.isDeviceProvisioned()
+ && (simState == TelephonyManager.SIM_STATE_ABSENT
+ || simState == TelephonyManager.SIM_STATE_PERM_DISABLED)) {
+ return CarrierTextManager.StatusMode.SimMissingLocked;
+ }
- // Assume we're NETWORK_LOCKED if not provisioned
- simState = missingAndNotProvisioned ? TelephonyManager.SIM_STATE_NETWORK_LOCKED : simState;
switch (simState) {
case TelephonyManager.SIM_STATE_ABSENT:
return CarrierTextManager.StatusMode.SimMissing;
case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
- return CarrierTextManager.StatusMode.SimMissingLocked;
+ return CarrierTextManager.StatusMode.NetworkLocked;
case TelephonyManager.SIM_STATE_NOT_READY:
return CarrierTextManager.StatusMode.SimNotReady;
case TelephonyManager.SIM_STATE_PIN_REQUIRED:
@@ -562,6 +565,8 @@
return CarrierTextManager.StatusMode.SimUnknown;
case TelephonyManager.SIM_STATE_CARD_IO_ERROR:
return CarrierTextManager.StatusMode.SimIoError;
+ case TelephonyManager.SIM_STATE_CARD_RESTRICTED:
+ return CarrierTextManager.StatusMode.SimRestricted;
}
return CarrierTextManager.StatusMode.SimUnknown;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 1d7c35d..7a0a24a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -104,7 +104,7 @@
case PROMPT_REASON_DEVICE_ADMIN:
return R.string.kg_prompt_reason_device_admin;
case PROMPT_REASON_USER_REQUEST:
- return R.string.kg_prompt_reason_user_request;
+ return R.string.kg_prompt_after_user_lockdown_password;
case PROMPT_REASON_PREPARE_FOR_UPDATE:
return R.string.kg_prompt_reason_timeout_password;
case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 64b1c50..be42376 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -311,7 +311,7 @@
resId = R.string.kg_prompt_reason_device_admin;
break;
case PROMPT_REASON_USER_REQUEST:
- resId = R.string.kg_prompt_reason_user_request;
+ resId = R.string.kg_prompt_after_user_lockdown_pattern;
break;
case PROMPT_REASON_PREPARE_FOR_UPDATE:
resId = R.string.kg_prompt_reason_timeout_pattern;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 5cb2c5c..687436c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -118,7 +118,7 @@
case PROMPT_REASON_DEVICE_ADMIN:
return R.string.kg_prompt_reason_device_admin;
case PROMPT_REASON_USER_REQUEST:
- return R.string.kg_prompt_reason_user_request;
+ return R.string.kg_prompt_after_user_lockdown_pin;
case PROMPT_REASON_PREPARE_FOR_UPDATE:
return R.string.kg_prompt_reason_timeout_pin;
case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 2bf8fb3..ae061c0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2045,11 +2045,47 @@
private final HashMap<Integer, Boolean> mIsUnlockWithFingerprintPossible = new HashMap<>();
/**
- * When we receive a
- * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast,
+ * When we receive a {@link android.content.Intent#ACTION_SIM_STATE_CHANGED} broadcast,
* and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange},
* we need a single object to pass to the handler. This class helps decode
* the intent and provide a {@link SimData} result.
+ *
+ * Below is the Sim state mapping matrixs:
+ * +---+-----------------------------------------------------+----------------------------+
+ * | |Telephony FWK broadcast with action |SystemUI mapping SIM state |
+ * | |android.content.Intent#ACTION_SIM_STATE_CHANGED |refer to android.telephony. |
+ * |NO.+-------------------------+---------------------------+TelephonyManager#getSimState|
+ * | |EXTRA_SIM_STATE |EXTRA_SIM_LOCKED_REASON | |
+ * | |(Intent#XXX) |(Intent#XXX) |TelephonyManager#SimState |
+ * +===+=====================================================+============================+
+ * |1 |SIM_STATE_UNKNOWN |always null |SIM_STATE_UNKNOWN |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |2 |SIM_STATE_ABSENT |always null |SIM_STATE_ABSENT |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |3 |SIM_STATE_CARD_IO_ERROR |SIM_STATE_CARD_IO_ERROR |SIM_STATE_CARD_IO_ERROR |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |4 |SIM_STATE_CARD_RESTRICTED|SIM_STATE_CARD_RESTRICTED |SIM_STATE_CARD_RESTRICTED |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |5 |SIM_STATE_LOCKED |SIM_LOCKED_ON_PIN |SIM_STATE_PIN_REQUIRED |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |6 |SIM_STATE_LOCKED |SIM_LOCKED_ON_PUK |SIM_STATE_PUK_REQUIRED |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |7 |SIM_STATE_LOCKED |SIM_LOCKED_NETWORK |SIM_STATE_NETWORK_LOCKED |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |8 |SIM_STATE_LOCKED |SIM_ABSENT_ON_PERM_DISABLED|SIM_STATE_PERM_DISABLED |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |9 |SIM_STATE_NOT_READY |always null |SIM_STATE_NOT_READY |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |10 |SIM_STATE_IMSI |always null |SIM_STATE_READY |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |11 |SIM_STATE_READY |always null |SIM_STATE_READY |
+ * +---+-------------------------+---------------------------+----------------------------+
+ * |12 |SIM_STATE_LOADED |always null |SIM_STATE_READY |
+ * +---+-------------------------+---------------------------+----------------------------+
+ *
+ * Note that, it seems #10 imsi ready case(i.e. SIM_STATE_IMSI) is never triggered from
+ * Android Pie(telephony FWK doesn't trigger this broadcast any more), but it is still
+ * OK keep this mapping logic.
*/
private static class SimData {
public int simState;
@@ -2063,26 +2099,16 @@
}
static SimData fromIntent(Intent intent) {
- int state;
if (!Intent.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
}
+ int state = TelephonyManager.SIM_STATE_UNKNOWN;
String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE);
int slotId = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0);
int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) {
- final String absentReason = intent
- .getStringExtra(Intent.EXTRA_SIM_LOCKED_REASON);
-
- if (Intent.SIM_ABSENT_ON_PERM_DISABLED.equals(
- absentReason)) {
- state = TelephonyManager.SIM_STATE_PERM_DISABLED;
- } else {
- state = TelephonyManager.SIM_STATE_ABSENT;
- }
- } else if (Intent.SIM_STATE_READY.equals(stateExtra)) {
- state = TelephonyManager.SIM_STATE_READY;
+ state = TelephonyManager.SIM_STATE_ABSENT;
} else if (Intent.SIM_STATE_LOCKED.equals(stateExtra)) {
final String lockedReason = intent
.getStringExtra(Intent.EXTRA_SIM_LOCKED_REASON);
@@ -2090,20 +2116,24 @@
state = TelephonyManager.SIM_STATE_PIN_REQUIRED;
} else if (Intent.SIM_LOCKED_ON_PUK.equals(lockedReason)) {
state = TelephonyManager.SIM_STATE_PUK_REQUIRED;
- } else {
- state = TelephonyManager.SIM_STATE_UNKNOWN;
+ } else if (Intent.SIM_LOCKED_NETWORK.equals(lockedReason)) {
+ state = TelephonyManager.SIM_STATE_NETWORK_LOCKED;
+ } else if (Intent.SIM_ABSENT_ON_PERM_DISABLED.equals(lockedReason)) {
+ state = TelephonyManager.SIM_STATE_PERM_DISABLED;
}
- } else if (Intent.SIM_LOCKED_NETWORK.equals(stateExtra)) {
- state = TelephonyManager.SIM_STATE_NETWORK_LOCKED;
} else if (Intent.SIM_STATE_CARD_IO_ERROR.equals(stateExtra)) {
state = TelephonyManager.SIM_STATE_CARD_IO_ERROR;
- } else if (Intent.SIM_STATE_LOADED.equals(stateExtra)
+ } else if (Intent.SIM_STATE_CARD_RESTRICTED.equals(stateExtra)) {
+ state = TelephonyManager.SIM_STATE_CARD_RESTRICTED;
+ } else if (Intent.SIM_STATE_NOT_READY.equals(stateExtra)) {
+ state = TelephonyManager.SIM_STATE_NOT_READY;
+ } else if (Intent.SIM_STATE_READY.equals(stateExtra)
+ || Intent.SIM_STATE_LOADED.equals(stateExtra)
|| Intent.SIM_STATE_IMSI.equals(stateExtra)) {
- // This is required because telephony doesn't return to "READY" after
+ // Mapping SIM_STATE_LOADED and SIM_STATE_IMSI to SIM_STATE_READY is required
+ // because telephony doesn't return to "READY" after
// these state transitions. See bug 7197471.
state = TelephonyManager.SIM_STATE_READY;
- } else {
- state = TelephonyManager.SIM_STATE_UNKNOWN;
}
return new SimData(state, slotId, subId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index c5e7e0d..ee046c2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -34,13 +34,11 @@
import com.android.systemui.complication.ComplicationLayoutParams.Position
import com.android.systemui.dreams.dagger.DreamOverlayModule
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
-import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.Companion.DREAM_ANIMATION_DURATION
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.BlurUtils
import com.android.systemui.statusbar.CrossFadeHelper
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
-import com.android.systemui.util.concurrency.DelayableExecutor
import javax.inject.Inject
import javax.inject.Named
import kotlinx.coroutines.flow.MutableStateFlow
@@ -129,6 +127,12 @@
)
}
}
+
+ launch {
+ transitionViewModel.transitionEnded.collect { _ ->
+ mOverlayStateController.setExitAnimationsRunning(false)
+ }
+ }
}
configController.removeCallback(configCallback)
@@ -251,9 +255,9 @@
}
/** Starts the dream content and dream overlay exit animations. */
- fun wakeUp(doneCallback: Runnable, executor: DelayableExecutor) {
+ fun wakeUp() {
cancelAnimations()
- executor.executeDelayed(doneCallback, DREAM_ANIMATION_DURATION.inWholeMilliseconds)
+ mOverlayStateController.setExitAnimationsRunning(true)
}
/** Cancels the dream content and dream overlay animations, if they're currently running. */
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index c22019e..ff07bb6 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -31,8 +31,6 @@
import android.view.View;
import android.view.ViewGroup;
-import androidx.annotation.NonNull;
-
import com.android.app.animation.Interpolators;
import com.android.dream.lowlight.LowLightTransitionCoordinator;
import com.android.systemui.R;
@@ -46,7 +44,6 @@
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.util.ViewController;
-import com.android.systemui.util.concurrency.DelayableExecutor;
import java.util.Arrays;
@@ -302,20 +299,15 @@
/**
* Handle the dream waking up and run any necessary animations.
- *
- * @param onAnimationEnd Callback to trigger once animations are finished.
- * @param callbackExecutor Executor to execute the callback on.
*/
- public void wakeUp(@NonNull Runnable onAnimationEnd,
- @NonNull DelayableExecutor callbackExecutor) {
+ public void wakeUp() {
// When swiping causes wakeup, do not run any animations as the dream should exit as soon
// as possible.
if (mWakingUpFromSwipe) {
- onAnimationEnd.run();
return;
}
- mDreamOverlayAnimationsController.wakeUp(onAnimationEnd, callbackExecutor);
+ mDreamOverlayAnimationsController.wakeUp();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 1da7900..d509015 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -116,6 +116,17 @@
}
};
+ private final DreamOverlayStateController.Callback mExitAnimationFinishedCallback =
+ new DreamOverlayStateController.Callback() {
+ @Override
+ public void onStateChanged() {
+ if (!mStateController.areExitAnimationsRunning()) {
+ mStateController.removeCallback(mExitAnimationFinishedCallback);
+ resetCurrentDreamOverlayLocked();
+ }
+ }
+ };
+
private final DreamOverlayStateController mStateController;
@VisibleForTesting
@@ -257,10 +268,10 @@
}
@Override
- public void onWakeUp(@NonNull Runnable onCompletedCallback) {
+ public void onWakeUp() {
if (mDreamOverlayContainerViewController != null) {
mDreamOverlayCallbackController.onWakeUp();
- mDreamOverlayContainerViewController.wakeUp(onCompletedCallback, mExecutor);
+ mDreamOverlayContainerViewController.wakeUp();
}
}
@@ -329,6 +340,11 @@
}
private void resetCurrentDreamOverlayLocked() {
+ if (mStateController.areExitAnimationsRunning()) {
+ mStateController.addCallback(mExitAnimationFinishedCallback);
+ return;
+ }
+
if (mStarted && mWindow != null) {
try {
mWindowManager.removeView(mWindow.getDecorView());
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index f3403f7..3f20540 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -266,7 +266,7 @@
/** Flag meant to guard the talkback fix for the KeyguardIndicationTextView */
// TODO(b/286563884): Tracking bug
@JvmField
- val KEYGUARD_TALKBACK_FIX = unreleasedFlag(238, "keyguard_talkback_fix")
+ val KEYGUARD_TALKBACK_FIX = releasedFlag(238, "keyguard_talkback_fix")
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@@ -748,4 +748,10 @@
@JvmField
val BIGPICTURE_NOTIFICATION_LAZY_LOADING =
unreleasedFlag(283447257, "bigpicture_notification_lazy_loading")
+
+ // 2900 - CentralSurfaces-related flags
+
+ // TODO(b/285174336): Tracking Bug
+ @JvmField
+ val USE_REPOS_FOR_BOUNCER_SHOWING = unreleasedFlag(2900, "use_repos_for_bouncer_showing")
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 2807107..76322ad 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -249,6 +249,7 @@
private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms
protected Handler mMainHandler;
private int mSmallestScreenWidthDp;
+ private int mOrientation;
private final Optional<CentralSurfaces> mCentralSurfacesOptional;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final DialogLaunchAnimator mDialogLaunchAnimator;
@@ -391,6 +392,7 @@
mRingerModeTracker = ringerModeTracker;
mMainHandler = handler;
mSmallestScreenWidthDp = resources.getConfiguration().smallestScreenWidthDp;
+ mOrientation = resources.getConfiguration().orientation;
mCentralSurfacesOptional = centralSurfacesOptional;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mDialogLaunchAnimator = dialogLaunchAnimator;
@@ -744,8 +746,10 @@
@Override
public void onConfigChanged(Configuration newConfig) {
if (mDialog != null && mDialog.isShowing()
- && (newConfig.smallestScreenWidthDp != mSmallestScreenWidthDp)) {
+ && (newConfig.smallestScreenWidthDp != mSmallestScreenWidthDp
+ || newConfig.orientation != mOrientation)) {
mSmallestScreenWidthDp = newConfig.smallestScreenWidthDp;
+ mOrientation = newConfig.orientation;
mDialog.refreshDialog();
}
}
@@ -2303,6 +2307,8 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ getWindow().setTitle(getContext().getString(
+ com.android.systemui.R.string.accessibility_quick_settings_power_menu));
initializeLayout();
mWindowDimAmount = getWindow().getAttributes().dimAmount;
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 94227bc..a2c940b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -187,10 +187,10 @@
final IRemoteAnimationRunner runner, final boolean lockscreenLiveWallpaperEnabled) {
return new IRemoteTransition.Stub() {
+ @GuardedBy("mLeashMap")
private final ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = new ArrayMap<>();
private final CounterRotator mCounterRotator = new CounterRotator();
-
@GuardedBy("mLeashMap")
private IRemoteTransitionFinishedCallback mFinishCallback = null;
@@ -200,40 +200,38 @@
throws RemoteException {
Slog.d(TAG, "Starts IRemoteAnimationRunner: info=" + info);
+ final RemoteAnimationTarget[] apps;
+ final RemoteAnimationTarget[] wallpapers;
+ final RemoteAnimationTarget[] nonApps = new RemoteAnimationTarget[0];
synchronized (mLeashMap) {
- final RemoteAnimationTarget[] apps =
- wrap(info, false /* wallpapers */, t, mLeashMap, mCounterRotator);
- final RemoteAnimationTarget[] wallpapers =
- wrap(info, true /* wallpapers */, t, mLeashMap, mCounterRotator);
- final RemoteAnimationTarget[] nonApps = new RemoteAnimationTarget[0];
-
- // Set alpha back to 1 for the independent changes because we will be animating
- // children instead.
- for (TransitionInfo.Change chg : info.getChanges()) {
- if (TransitionInfo.isIndependent(chg, info)) {
- t.setAlpha(chg.getLeash(), 1.f);
- }
- }
- initAlphaForAnimationTargets(t, apps);
- if (lockscreenLiveWallpaperEnabled) {
- initAlphaForAnimationTargets(t, wallpapers);
- }
- t.apply();
+ apps = wrap(info, false /* wallpapers */, t, mLeashMap, mCounterRotator);
+ wallpapers = wrap(info, true /* wallpapers */, t, mLeashMap, mCounterRotator);
mFinishCallback = finishCallback;
- runner.onAnimationStart(
- getTransitionOldType(info.getType(), info.getFlags(), apps),
- apps, wallpapers, nonApps,
- new IRemoteAnimationFinishedCallback.Stub() {
- @Override
- public void onAnimationFinished() throws RemoteException {
- synchronized (mLeashMap) {
- Slog.d(TAG, "Finish IRemoteAnimationRunner.");
- finish();
- }
- }
- }
- );
}
+
+ // Set alpha back to 1 for the independent changes because we will be animating
+ // children instead.
+ for (TransitionInfo.Change chg : info.getChanges()) {
+ if (TransitionInfo.isIndependent(chg, info)) {
+ t.setAlpha(chg.getLeash(), 1.f);
+ }
+ }
+ initAlphaForAnimationTargets(t, apps);
+ if (lockscreenLiveWallpaperEnabled) {
+ initAlphaForAnimationTargets(t, wallpapers);
+ }
+ t.apply();
+
+ runner.onAnimationStart(
+ getTransitionOldType(info.getType(), info.getFlags(), apps),
+ apps, wallpapers, nonApps,
+ new IRemoteAnimationFinishedCallback.Stub() {
+ @Override
+ public void onAnimationFinished() throws RemoteException {
+ Slog.d(TAG, "Finish IRemoteAnimationRunner.");
+ finish();
+ }
+ });
}
public void mergeAnimation(IBinder candidateTransition, TransitionInfo candidateInfo,
@@ -247,10 +245,8 @@
}
try {
- synchronized (mLeashMap) {
- runner.onAnimationCancelled();
- finish();
- }
+ runner.onAnimationCancelled();
+ finish();
} catch (RemoteException e) {
// nothing, we'll just let it finish on its own I guess.
}
@@ -264,18 +260,22 @@
}
}
- @GuardedBy("mLeashMap")
private void finish() throws RemoteException {
+ IRemoteTransitionFinishedCallback finishCallback = null;
SurfaceControl.Transaction finishTransaction = null;
- if (mCounterRotator.getSurface() != null
- && mCounterRotator.getSurface().isValid()) {
- finishTransaction = new SurfaceControl.Transaction();
- mCounterRotator.cleanUp(finishTransaction);
- }
- mLeashMap.clear();
- final IRemoteTransitionFinishedCallback finishCallback = mFinishCallback;
- if (finishCallback != null) {
+
+ synchronized (mLeashMap) {
+ if (mCounterRotator.getSurface() != null
+ && mCounterRotator.getSurface().isValid()) {
+ finishTransaction = new SurfaceControl.Transaction();
+ mCounterRotator.cleanUp(finishTransaction);
+ }
+ mLeashMap.clear();
+ finishCallback = mFinishCallback;
mFinishCallback = null;
+ }
+
+ if (finishCallback != null) {
finishCallback.onTransitionFinished(null /* wct */, finishTransaction);
} else if (finishTransaction != null) {
finishTransaction.apply();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0e0cf74..5bf56a1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -18,6 +18,7 @@
import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
@@ -32,10 +33,11 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.LOCKSCREEN_ANIMATION_DURATION_MS;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
+import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -87,9 +89,11 @@
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl.Transaction;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants;
import android.view.animation.Animation;
@@ -127,12 +131,14 @@
import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.dagger.KeyguardModule;
+import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -162,6 +168,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+import kotlinx.coroutines.CoroutineDispatcher;
/**
* Mediates requests related to the keyguard. This includes queries about the
@@ -435,11 +444,6 @@
private final int mDreamOpenAnimationDuration;
/**
- * The duration in milliseconds of the dream close animation.
- */
- private final int mDreamCloseAnimationDuration;
-
- /**
* The animation used for hiding keyguard. This is used to fetch the animation timings if
* WindowManager is not providing us with them.
*/
@@ -845,6 +849,8 @@
return KeyguardSecurityView.PROMPT_REASON_RESTART;
} else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) != 0) {
return KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
+ } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN) != 0) {
+ return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
} else if ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) {
return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
} else if (trustAgentsEnabled
@@ -1128,49 +1134,57 @@
return;
}
- final RemoteAnimationTarget primary = apps[0];
+ mRemoteAnimationTarget = apps[0];
final boolean isDream = (apps[0].taskInfo != null
&& apps[0].taskInfo.topActivityType
== WindowConfiguration.ACTIVITY_TYPE_DREAM);
- final SyncRtSurfaceTransactionApplier applier =
- new SyncRtSurfaceTransactionApplier(
- mKeyguardViewControllerLazy.get().getViewRootImpl().getView());
+ final View localView = mKeyguardViewControllerLazy.get()
+ .getViewRootImpl().getView();
+ final SyncRtSurfaceTransactionApplier applier =
+ new SyncRtSurfaceTransactionApplier(localView);
mContext.getMainExecutor().execute(() -> {
if (mUnoccludeAnimator != null) {
mUnoccludeAnimator.cancel();
}
+ if (isDream) {
+ initAlphaForAnimationTargets(wallpapers);
+ getRemoteSurfaceAlphaApplier().accept(0.0f);
+ mDreamingToLockscreenTransitionViewModel.get()
+ .startTransition();
+ return;
+ }
+
mUnoccludeAnimator = ValueAnimator.ofFloat(1f, 0f);
- mUnoccludeAnimator.setDuration(isDream ? mDreamCloseAnimationDuration
- : UNOCCLUDE_ANIMATION_DURATION);
+ mUnoccludeAnimator.setDuration(UNOCCLUDE_ANIMATION_DURATION);
mUnoccludeAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE);
mUnoccludeAnimator.addUpdateListener(
animation -> {
final float animatedValue =
(float) animation.getAnimatedValue();
- final float surfaceHeight = primary.screenSpaceBounds.height();
+ final float surfaceHeight =
+ mRemoteAnimationTarget.screenSpaceBounds.height();
// Fade for all types of activities.
SyncRtSurfaceTransactionApplier.SurfaceParams.Builder
paramsBuilder =
new SyncRtSurfaceTransactionApplier.SurfaceParams
- .Builder(primary.leash)
+ .Builder(mRemoteAnimationTarget.leash)
.withAlpha(animatedValue);
- // Set translate if the occluding activity isn't Dream.
- if (!isDream) {
- mUnoccludeMatrix.setTranslate(
- 0f,
- (1f - animatedValue)
- * surfaceHeight
- * UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT);
- paramsBuilder.withMatrix(mUnoccludeMatrix).withCornerRadius(
- mWindowCornerRadius);
- }
+ mUnoccludeMatrix.setTranslate(
+ 0f,
+ (1f - animatedValue)
+ * surfaceHeight
+ * UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT);
+
+ paramsBuilder.withMatrix(mUnoccludeMatrix).withCornerRadius(
+ mWindowCornerRadius);
+
applier.scheduleApply(paramsBuilder.build());
});
mUnoccludeAnimator.addListener(new AnimatorListenerAdapter() {
@@ -1192,6 +1206,34 @@
}
};
+ private static void initAlphaForAnimationTargets(
+ @android.annotation.NonNull RemoteAnimationTarget[] targets
+ ) {
+ for (RemoteAnimationTarget target : targets) {
+ if (target.mode != MODE_OPENING) continue;
+
+ try (Transaction t = new Transaction()) {
+ t.setAlpha(target.leash, 1.f);
+ t.apply();
+ }
+ }
+ }
+
+ private Consumer<Float> getRemoteSurfaceAlphaApplier() {
+ return (Float alpha) -> {
+ if (mRemoteAnimationTarget == null) return;
+ final View localView = mKeyguardViewControllerLazy.get().getViewRootImpl().getView();
+ final SyncRtSurfaceTransactionApplier applier =
+ new SyncRtSurfaceTransactionApplier(localView);
+ SyncRtSurfaceTransactionApplier.SurfaceParams
+ params =
+ new SyncRtSurfaceTransactionApplier.SurfaceParams
+ .Builder(mRemoteAnimationTarget.leash)
+ .withAlpha(alpha).build();
+ applier.scheduleApply(params);
+ };
+ }
+
private DeviceConfigProxy mDeviceConfig;
private DozeParameters mDozeParameters;
@@ -1221,6 +1263,10 @@
private FeatureFlags mFeatureFlags;
private final UiEventLogger mUiEventLogger;
private final SessionTracker mSessionTracker;
+ private final CoroutineDispatcher mMainDispatcher;
+ private final Lazy<DreamingToLockscreenTransitionViewModel>
+ mDreamingToLockscreenTransitionViewModel;
+ private RemoteAnimationTarget mRemoteAnimationTarget;
/**
* Injected constructor. See {@link KeyguardModule}.
@@ -1256,7 +1302,9 @@
Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy,
Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
Lazy<ScrimController> scrimControllerLazy,
- FeatureFlags featureFlags) {
+ FeatureFlags featureFlags,
+ @Main CoroutineDispatcher mainDispatcher,
+ Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel) {
mContext = context;
mUserTracker = userTracker;
mFalsingCollector = falsingCollector;
@@ -1311,11 +1359,13 @@
mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
mDreamOpenAnimationDuration = (int) DREAMING_ANIMATION_DURATION_MS;
- mDreamCloseAnimationDuration = (int) LOCKSCREEN_ANIMATION_DURATION_MS;
mFeatureFlags = featureFlags;
mUiEventLogger = uiEventLogger;
mSessionTracker = sessionTracker;
+
+ mMainDispatcher = mainDispatcher;
+ mDreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel;
}
public void userActivity() {
@@ -1434,6 +1484,13 @@
mUpdateMonitor.registerCallback(mUpdateCallback);
adjustStatusBarLocked();
mDreamOverlayStateController.addCallback(mDreamOverlayStateCallback);
+
+ ViewRootImpl viewRootImpl = mKeyguardViewControllerLazy.get().getViewRootImpl();
+ if (viewRootImpl != null) {
+ collectFlow(viewRootImpl.getView(),
+ mDreamingToLockscreenTransitionViewModel.get().getDreamOverlayAlpha(),
+ getRemoteSurfaceAlphaApplier(), mMainDispatcher);
+ }
}
// Most services aren't available until the system reaches the ready state, so we
// send it here when the device first boots.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index d7c039d..ab79c80 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -37,6 +37,7 @@
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager;
@@ -51,6 +52,7 @@
import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceModule;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLoggerImpl;
+import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.settings.UserTracker;
@@ -72,6 +74,8 @@
import java.util.concurrent.Executor;
+import kotlinx.coroutines.CoroutineDispatcher;
+
/**
* Dagger Module providing keyguard.
*/
@@ -128,7 +132,9 @@
Lazy<NotificationShadeWindowController> notificationShadeWindowController,
Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
Lazy<ScrimController> scrimControllerLazy,
- FeatureFlags featureFlags) {
+ FeatureFlags featureFlags,
+ @Main CoroutineDispatcher mainDispatcher,
+ Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel) {
return new KeyguardViewMediator(
context,
uiEventLogger,
@@ -162,7 +168,9 @@
notificationShadeWindowController,
activityLaunchAnimator,
scrimControllerLazy,
- featureFlags);
+ featureFlags,
+ mainDispatcher,
+ dreamingToLockscreenTransitionViewModel);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 100bc59..358ab01 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -160,35 +160,28 @@
// An animator was provided, so use it to run the transition
animator.setFloatValues(startingValue, 1f)
animator.duration = ((1f - startingValue) * animator.duration).toLong()
- val updateListener =
- object : AnimatorUpdateListener {
- override fun onAnimationUpdate(animation: ValueAnimator) {
- emitTransition(
- TransitionStep(
- info,
- (animation.getAnimatedValue() as Float),
- TransitionState.RUNNING
- )
- )
- }
- }
+ val updateListener = AnimatorUpdateListener { animation ->
+ emitTransition(
+ TransitionStep(
+ info,
+ (animation.animatedValue as Float),
+ TransitionState.RUNNING
+ )
+ )
+ }
val adapter =
object : AnimatorListenerAdapter() {
override fun onAnimationStart(animation: Animator) {
emitTransition(TransitionStep(info, startingValue, TransitionState.STARTED))
}
override fun onAnimationCancel(animation: Animator) {
- endAnimation(animation, lastStep.value, TransitionState.CANCELED)
+ endAnimation(lastStep.value, TransitionState.CANCELED)
}
override fun onAnimationEnd(animation: Animator) {
- endAnimation(animation, 1f, TransitionState.FINISHED)
+ endAnimation(1f, TransitionState.FINISHED)
}
- private fun endAnimation(
- animation: Animator,
- value: Float,
- state: TransitionState
- ) {
+ private fun endAnimation(value: Float, state: TransitionState) {
emitTransition(TransitionStep(info, value, state))
animator.removeListener(this)
animator.removeUpdateListener(updateListener)
@@ -201,7 +194,7 @@
return@startTransition null
}
?: run {
- emitTransition(TransitionStep(info, 0f, TransitionState.STARTED))
+ emitTransition(TransitionStep(info, startingValue, TransitionState.STARTED))
// No animator, so it's manual. Provide a mechanism to callback
updateTransitionId = UUID.randomUUID()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 323fc31..ee2c2df 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -52,7 +52,7 @@
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (wakefulnessModel, lastStartedTransition) ->
if (
- wakefulnessModel.isStartingToWake() &&
+ wakefulnessModel.isStartingToWakeOrAwake() &&
lastStartedTransition.to == KeyguardState.DOZING
) {
keyguardTransitionRepository.startTransition(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 36c8eb1..ccf4bc1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -23,7 +23,6 @@
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
-import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
@@ -48,39 +47,23 @@
) : TransitionInteractor(FromDreamingTransitionInteractor::class.simpleName!!) {
override fun start() {
- listenForDreamingToLockscreen()
listenForDreamingToOccluded()
listenForDreamingToGone()
listenForDreamingToDozing()
}
- private fun listenForDreamingToLockscreen() {
+ fun startToLockscreenTransition() {
scope.launch {
- keyguardInteractor.isAbleToDream
- .sample(
- combine(
- keyguardInteractor.dozeTransitionModel,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
- ::Pair
- ),
- ::toTriple
+ if (keyguardTransitionInteractor.startedKeyguardState.value == KeyguardState.DREAMING) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ KeyguardState.DREAMING,
+ KeyguardState.LOCKSCREEN,
+ getAnimator(TO_LOCKSCREEN_DURATION),
+ )
)
- .collect { (isDreaming, dozeTransitionModel, lastStartedTransition) ->
- if (
- !isDreaming &&
- isDozeOff(dozeTransitionModel.to) &&
- lastStartedTransition.to == KeyguardState.DREAMING
- ) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.DREAMING,
- KeyguardState.LOCKSCREEN,
- getAnimator(TO_LOCKSCREEN_DURATION),
- )
- )
- }
- }
+ }
}
}
@@ -173,6 +156,6 @@
companion object {
private val DEFAULT_DURATION = 500.milliseconds
- val TO_LOCKSCREEN_DURATION = 1183.milliseconds
+ val TO_LOCKSCREEN_DURATION = 1167.milliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 3cf9a9e..c44435e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -111,7 +111,7 @@
isDreaming && isDozeOff(dozeTransitionModel.to)
}
.sample(wakefulnessModel) { isAbleToDream, wakefulnessModel ->
- isAbleToDream && wakefulnessModel.isStartingToWake()
+ isAbleToDream && wakefulnessModel.isStartingToWakeOrAwake()
}
.flatMapLatest { isAbleToDream ->
flow {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index da0ada1..42f12f8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -18,6 +18,7 @@
package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
@@ -29,10 +30,14 @@
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.stateIn
/** Encapsulates business-logic related to the keyguard transitions. */
@SysUISingleton
@@ -40,6 +45,7 @@
@Inject
constructor(
private val repository: KeyguardTransitionRepository,
+ @Application val scope: CoroutineScope,
) {
/** (any)->GONE transition information */
val anyStateToGoneTransition: Flow<TransitionStep> =
@@ -108,10 +114,17 @@
val finishedKeyguardTransitionStep: Flow<TransitionStep> =
repository.transitions.filter { step -> step.transitionState == TransitionState.FINISHED }
- /** The last completed [KeyguardState] transition */
- val finishedKeyguardState: Flow<KeyguardState> =
- finishedKeyguardTransitionStep.map { step -> step.to }
+ /** The destination state of the last started transition */
+ val startedKeyguardState: StateFlow<KeyguardState> =
+ startedKeyguardTransitionStep
+ .map { step -> step.to }
+ .stateIn(scope, SharingStarted.Eagerly, KeyguardState.OFF)
+ /** The last completed [KeyguardState] transition */
+ val finishedKeyguardState: StateFlow<KeyguardState> =
+ finishedKeyguardTransitionStep
+ .map { step -> step.to }
+ .stateIn(scope, SharingStarted.Eagerly, LOCKSCREEN)
/**
* The amount of transition into or out of the given [KeyguardState].
*
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
index 7ca90ba..52e15be 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
@@ -29,6 +29,8 @@
fun isStartingToSleepOrAsleep() = isStartingToSleep() || state == WakefulnessState.ASLEEP
+ fun isStartingToWakeOrAwake() = isStartingToWake() || state == WakefulnessState.AWAKE
+
fun isStartingToSleepFromPowerButton() =
isStartingToSleep() && lastWakeReason == WakeSleepReason.POWER_BUTTON
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
index 2c9a9b3..9ca4bd6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
@@ -16,15 +16,17 @@
package com.android.systemui.keyguard.ui.viewmodel
-import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
-import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
/**
* Breaks down DREAMING->LOCKSCREEN transition into discrete steps for corresponding views to
@@ -34,22 +36,32 @@
class DreamingToLockscreenTransitionViewModel
@Inject
constructor(
- private val interactor: KeyguardTransitionInteractor,
+ keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ private val fromDreamingTransitionInteractor: FromDreamingTransitionInteractor
) {
+ fun startTransition() = fromDreamingTransitionInteractor.startToLockscreenTransition()
+
private val transitionAnimation =
KeyguardTransitionAnimationFlow(
transitionDuration = TO_LOCKSCREEN_DURATION,
- transitionFlow = interactor.dreamingToLockscreenTransition,
+ transitionFlow = keyguardTransitionInteractor.dreamingToLockscreenTransition,
)
+ val transitionEnded =
+ keyguardTransitionInteractor.dreamingToLockscreenTransition.filter { step ->
+ step.transitionState == TransitionState.FINISHED ||
+ step.transitionState == TransitionState.CANCELED
+ }
+
/** Dream overlay y-translation on exit */
fun dreamOverlayTranslationY(translatePx: Int): Flow<Float> {
return transitionAnimation.createFlow(
- duration = 600.milliseconds,
+ duration = TO_LOCKSCREEN_DURATION,
onStep = { it * translatePx },
- interpolator = EMPHASIZED_ACCELERATE,
+ interpolator = EMPHASIZED,
)
}
+
/** Dream overlay views alpha - fade out */
val dreamOverlayAlpha: Flow<Float> =
transitionAnimation.createFlow(
@@ -65,7 +77,7 @@
// Reset on cancel or finish
onFinish = { 0f },
onCancel = { 0f },
- interpolator = EMPHASIZED_DECELERATE,
+ interpolator = EMPHASIZED,
)
}
@@ -76,12 +88,4 @@
duration = 250.milliseconds,
onStep = { it },
)
-
- companion object {
- /* Length of time before ending the dream activity, in order to start unoccluding */
- val DREAM_ANIMATION_DURATION = 250.milliseconds
- @JvmField
- val LOCKSCREEN_ANIMATION_DURATION_MS =
- (TO_LOCKSCREEN_DURATION - DREAM_ANIMATION_DURATION).inWholeMilliseconds
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
index c6187dd..a3ae67d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
@@ -33,7 +33,7 @@
class LockscreenToDreamingTransitionViewModel
@Inject
constructor(
- private val interactor: KeyguardTransitionInteractor,
+ interactor: KeyguardTransitionInteractor,
) {
private val transitionAnimation =
KeyguardTransitionAnimationFlow(
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index b96ca7a..3b32313e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -224,7 +224,6 @@
return LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION;
}
});
- controller.overrideIconTintForNavMode(true);
return controller;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt b/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt
index 3eec7fa0e..ff57a73 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/QsBatteryModeController.kt
@@ -39,19 +39,12 @@
* [cutout]. We don't show battery estimation in qqs header on the devices with center cutout.
* The result might be null when the battery icon is invisible during the qs-qqs transition
* animation.
+ *
+ * Note: short-circuiting this value until a comprehensive fix for b/282044659 is finished.
*/
@BatteryMeterView.BatteryPercentMode
fun getBatteryMode(cutout: DisplayCutout?, qsExpandedFraction: Float): Int? =
- when {
- qsExpandedFraction > fadeInStartFraction -> BatteryMeterView.MODE_ESTIMATE
- qsExpandedFraction < fadeOutCompleteFraction ->
- if (hasCenterCutout(cutout)) {
- BatteryMeterView.MODE_ON
- } else {
- BatteryMeterView.MODE_ESTIMATE
- }
- else -> null
- }
+ BatteryMeterView.MODE_ON
fun updateResources() {
fadeInStartFraction =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 1cd0f08..648ece5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -475,6 +475,13 @@
*/
private boolean mShouldDelayWakeUpAnimation = false;
+ /**
+ * Whether we should delay the AOD->Lockscreen animation.
+ * If false, the animation will start in onStartedWakingUp().
+ * If true, the animation will start in onFinishedWakingUp().
+ */
+ private boolean mShouldDelayLockscreenTransitionFromAod = false;
+
private final Object mQueueLock = new Object();
private final PulseExpansionHandler mPulseExpansionHandler;
@@ -3242,7 +3249,10 @@
updateVisibleToUser();
updateIsKeyguard();
- if (!mFeatureFlags.isEnabled(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD)) {
+ mShouldDelayLockscreenTransitionFromAod = mDozeParameters.getAlwaysOn()
+ && mFeatureFlags.isEnabled(
+ Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD);
+ if (!mShouldDelayLockscreenTransitionFromAod) {
startLockscreenTransitionFromAod();
}
});
@@ -3251,8 +3261,7 @@
/**
* Private helper for starting the LOCKSCREEN_TRANSITION_FROM_AOD animation - only necessary
- * so we can start it from either onFinishedWakingUp() or onFinishedWakingUp() depending
- * on a flag value.
+ * so we can start it from either onFinishedWakingUp() or onFinishedWakingUp().
*/
private void startLockscreenTransitionFromAod() {
// stopDozing() starts the LOCKSCREEN_TRANSITION_FROM_AOD animation.
@@ -3273,7 +3282,7 @@
@Override
public void onFinishedWakingUp() {
- if (mFeatureFlags.isEnabled(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD)) {
+ if (mShouldDelayLockscreenTransitionFromAod) {
mNotificationShadeWindowController.batchApplyWindowLayoutParams(
this::startLockscreenTransitionFromAod);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 7bc4fc3..ae70384 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -115,7 +115,6 @@
};
private final Context mContext;
- private Boolean mOverrideIconTintForNavMode;
@AssistedInject
public LightBarTransitionsController(
@@ -276,19 +275,11 @@
}
/**
- * Specify an override value to return for {@link #overrideIconTintForNavMode(boolean)}.
- */
- public void overrideIconTintForNavMode(boolean overrideValue) {
- mOverrideIconTintForNavMode = overrideValue;
- }
- /**
* Return whether to use the tint calculated in this class for nav icons.
*/
public boolean supportsIconTintForNavMode(int navigationMode) {
// In gesture mode, we already do region sampling to update tint based on content beneath.
- return mOverrideIconTintForNavMode != null
- ? mOverrideIconTintForNavMode
- : !QuickStepContract.isGesturalMode(navigationMode);
+ return !QuickStepContract.isGesturalMode(navigationMode);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
index 2b4f51c..4c6374b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapter.kt
@@ -35,7 +35,10 @@
) : BaseAdapter() {
protected open val users: List<UserRecord>
- get() = controller.users.filter { !controller.isKeyguardShowing || !it.isRestricted }
+ get() = controller.users.filter {
+ (!controller.isKeyguardShowing || !it.isRestricted) &&
+ (controller.isUserSwitcherEnabled || it.isCurrent)
+ }
init {
controller.addAdapter(WeakReference(this))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
index 1e223b1..f88339a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
@@ -67,6 +67,9 @@
val isSimpleUserSwitcher: Boolean
get() = userInteractor.isSimpleUserSwitcher
+ val isUserSwitcherEnabled: Boolean
+ get() = userInteractor.isUserSwitcherEnabled
+
/** The [UserRecord] of the current user or `null` when none. */
val currentUserRecord: UserRecord?
get() = userInteractor.selectedUserRecord.value
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
index a0b56aa..3de75ca 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -105,6 +105,8 @@
fun getSelectedUserInfo(): UserInfo
fun isSimpleUserSwitcher(): Boolean
+
+ fun isUserSwitcherEnabled(): Boolean
}
@SysUISingleton
@@ -206,6 +208,10 @@
return _userSwitcherSettings.value.isSimpleUserSwitcher
}
+ override fun isUserSwitcherEnabled(): Boolean {
+ return _userSwitcherSettings.value.isUserSwitcherEnabled
+ }
+
private fun observeUserSwitching() {
conflatedCallbackFlow {
val callback =
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
index 27c348b..a487f53 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -294,6 +294,10 @@
val isSimpleUserSwitcher: Boolean
get() = repository.isSimpleUserSwitcher()
+
+ val isUserSwitcherEnabled: Boolean
+ get() = repository.isUserSwitcherEnabled()
+
val keyguardUpdateMonitorCallback =
object : KeyguardUpdateMonitorCallback() {
override fun onKeyguardGoingAway() {
@@ -370,6 +374,7 @@
}
pw.println("isSimpleUserSwitcher=$isSimpleUserSwitcher")
+ pw.println("isUserSwitcherEnabled=$isUserSwitcherEnabled")
pw.println("isGuestUserAutoCreated=$isGuestUserAutoCreated")
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
index 48a8d1b..e7d420b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
@@ -561,6 +561,66 @@
captor.getValue().carrierText);
}
+ @Test
+ public void testGetStatusForIccState() {
+ when(mKeyguardUpdateMonitor.isDeviceProvisioned()).thenReturn(false);
+ assertEquals(CarrierTextManager.StatusMode.SimMissingLocked,
+ mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_ABSENT));
+ assertEquals(CarrierTextManager.StatusMode.NetworkLocked,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_NETWORK_LOCKED));
+ assertEquals(CarrierTextManager.StatusMode.SimNotReady,
+ mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_NOT_READY));
+ assertEquals(CarrierTextManager.StatusMode.SimLocked,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_PIN_REQUIRED));
+ assertEquals(CarrierTextManager.StatusMode.SimPukLocked,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_PUK_REQUIRED));
+ assertEquals(CarrierTextManager.StatusMode.Normal,
+ mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_READY));
+ assertEquals(CarrierTextManager.StatusMode.SimMissingLocked,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_PERM_DISABLED));
+ assertEquals(CarrierTextManager.StatusMode.SimUnknown,
+ mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_UNKNOWN));
+ assertEquals(CarrierTextManager.StatusMode.SimIoError,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_CARD_IO_ERROR));
+ assertEquals(CarrierTextManager.StatusMode.SimRestricted,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_CARD_RESTRICTED));
+
+ when(mKeyguardUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
+ assertEquals(CarrierTextManager.StatusMode.SimMissing,
+ mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_ABSENT));
+ assertEquals(CarrierTextManager.StatusMode.NetworkLocked,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_NETWORK_LOCKED));
+ assertEquals(CarrierTextManager.StatusMode.SimNotReady,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_NOT_READY));
+ assertEquals(CarrierTextManager.StatusMode.SimLocked,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_PIN_REQUIRED));
+ assertEquals(CarrierTextManager.StatusMode.SimPukLocked,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_PUK_REQUIRED));
+ assertEquals(CarrierTextManager.StatusMode.Normal,
+ mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_READY));
+ assertEquals(CarrierTextManager.StatusMode.SimPermDisabled,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_PERM_DISABLED));
+ assertEquals(CarrierTextManager.StatusMode.SimUnknown,
+ mCarrierTextManager.getStatusForIccState(TelephonyManager.SIM_STATE_UNKNOWN));
+ assertEquals(CarrierTextManager.StatusMode.SimIoError,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_CARD_IO_ERROR));
+ assertEquals(CarrierTextManager.StatusMode.SimRestricted,
+ mCarrierTextManager.getStatusForIccState(
+ TelephonyManager.SIM_STATE_CARD_RESTRICTED));
+ }
+
private Context getContextSpyForStickyBroadcast(Intent returnVal) {
Context contextSpy = spy(mContext);
doReturn(returnVal).when(contextSpy).registerReceiver(eq(null), any(IntentFilter.class));
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 3f1560b..e9a9f3a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -47,6 +47,7 @@
import com.android.systemui.util.mockito.mock
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.yield
import org.junit.Assert.assertEquals
import org.junit.Before
@@ -118,7 +119,7 @@
featureFlags = featureFlags,
bouncerRepository = bouncerRepository,
),
- KeyguardTransitionInteractor(repository = transitionRepository),
+ KeyguardTransitionInteractor(transitionRepository, TestScope().backgroundScope),
broadcastDispatcher,
batteryController,
keyguardUpdateMonitor,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index de306d6..1e675f8 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -167,6 +167,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -672,6 +673,130 @@
}
@Test
+ public void testHandleSimStateChange_Unknown() {
+ Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_UNKNOWN);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, false));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_UNKNOWN,
+ mKeyguardUpdateMonitor.getCachedSimState());
+ }
+
+ @Test
+ public void testHandleSimStateChange_Absent() {
+ Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_ABSENT);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, false));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_ABSENT,
+ mKeyguardUpdateMonitor.getCachedSimState());
+ }
+
+ @Test
+ public void testHandleSimStateChange_CardIOError() {
+ Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_CARD_IO_ERROR);
+ intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_STATE_CARD_IO_ERROR);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, false));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_CARD_IO_ERROR,
+ mKeyguardUpdateMonitor.getCachedSimState());
+ }
+
+ @Test
+ public void testHandleSimStateChange_CardRestricted() {
+ Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_CARD_RESTRICTED);
+ intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_STATE_CARD_RESTRICTED);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, false));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_CARD_RESTRICTED,
+ mKeyguardUpdateMonitor.getCachedSimState());
+ }
+
+ @Test
+ public void testHandleSimStateChange_Locked() {
+ Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_LOCKED);
+
+ // locked on PIN1
+ intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_LOCKED_ON_PIN);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, true));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_PIN_REQUIRED,
+ mKeyguardUpdateMonitor.getCachedSimState());
+
+ // locked on PUK1
+ intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_LOCKED_ON_PUK);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, true));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_PUK_REQUIRED,
+ mKeyguardUpdateMonitor.getCachedSimState());
+
+ // locked on network personalization
+ intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_LOCKED_NETWORK);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, true));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_NETWORK_LOCKED,
+ mKeyguardUpdateMonitor.getCachedSimState());
+
+ // permanently disabled due to puk fails
+ intent.putExtra(Intent.EXTRA_SIM_LOCKED_REASON, Intent.SIM_ABSENT_ON_PERM_DISABLED);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, true));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_PERM_DISABLED,
+ mKeyguardUpdateMonitor.getCachedSimState());
+ }
+
+ @Test
+ public void testHandleSimStateChange_NotReady() {
+ Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_NOT_READY);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, false));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_NOT_READY,
+ mKeyguardUpdateMonitor.getCachedSimState());
+ }
+
+ @Test
+ public void testHandleSimStateChange_Ready() {
+ Intent intent = new Intent(Intent.ACTION_SIM_STATE_CHANGED);
+
+ // ICC IMSI is ready in property
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_IMSI);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, false));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_READY,
+ mKeyguardUpdateMonitor.getCachedSimState());
+
+ // ICC is ready to access
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_READY);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, false));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_READY,
+ mKeyguardUpdateMonitor.getCachedSimState());
+
+ // all ICC records, including IMSI, are loaded
+ intent.putExtra(Intent.EXTRA_SIM_STATE, Intent.SIM_STATE_LOADED);
+ mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
+ putPhoneInfo(intent, null, true));
+ mTestableLooper.processAllMessages();
+ Assert.assertEquals(TelephonyManager.SIM_STATE_READY,
+ mKeyguardUpdateMonitor.getCachedSimState());
+ }
+
+ @Test
public void testTriesToAuthenticateFingerprint_whenKeyguard() {
mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
mTestableLooper.processAllMessages();
@@ -3122,6 +3247,7 @@
private class TestableKeyguardUpdateMonitor extends KeyguardUpdateMonitor {
AtomicBoolean mSimStateChanged = new AtomicBoolean(false);
+ AtomicInteger mCachedSimState = new AtomicInteger(-1);
protected TestableKeyguardUpdateMonitor(Context context) {
super(context, mUserTracker,
@@ -3144,9 +3270,14 @@
return mSimStateChanged.getAndSet(false);
}
+ public int getCachedSimState() {
+ return mCachedSimState.getAndSet(-1);
+ }
+
@Override
protected void handleSimStateChange(int subId, int slotId, int state) {
mSimStateChanged.set(true);
+ mCachedSimState.set(state);
super.handleSimStateChange(subId, slotId, state);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index 456702b..84e58be 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -159,7 +159,8 @@
mVibrator,
mAuthRippleController,
mResources,
- new KeyguardTransitionInteractor(mTransitionRepository),
+ new KeyguardTransitionInteractor(mTransitionRepository,
+ TestScopeProvider.getTestScope().getBackgroundScope()),
new KeyguardInteractor(
new FakeKeyguardRepository(),
mCommandQueue,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/TestScopeProvider.kt b/packages/SystemUI/tests/src/com/android/keyguard/TestScopeProvider.kt
new file mode 100644
index 0000000..073c7fe
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/TestScopeProvider.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.keyguard
+
+import kotlinx.coroutines.test.TestScope
+
+class TestScopeProvider {
+ companion object {
+ @JvmStatic fun getTestScope() = TestScope()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
index 1f2b64d..263ce1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/LogContextInteractorImplTest.kt
@@ -56,6 +56,7 @@
foldProvider,
KeyguardTransitionInteractor(
keyguardTransitionRepository,
+ testScope.backgroundScope
),
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
index 039682c..a00e545 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
@@ -11,7 +11,6 @@
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
import com.android.systemui.statusbar.BlurUtils
import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
@@ -23,9 +22,7 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
-import org.mockito.Mockito.anyLong
import org.mockito.Mockito.atLeastOnce
-import org.mockito.Mockito.eq
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
@@ -92,16 +89,10 @@
}
@Test
- fun testWakeUpCallsExecutor() {
- val mockExecutor: DelayableExecutor = mock()
- val mockCallback: Runnable = mock()
+ fun testWakeUpSetsExitAnimationsRunning() {
+ controller.wakeUp()
- controller.wakeUp(
- doneCallback = mockCallback,
- executor = mockExecutor,
- )
-
- verify(mockExecutor).executeDelayed(eq(mockCallback), anyLong())
+ verify(stateController).setExitAnimationsRunning(true)
}
@Test
@@ -112,10 +103,7 @@
verify(mockStartAnimator, never()).cancel()
- controller.wakeUp(
- doneCallback = mock(),
- executor = mock(),
- )
+ controller.wakeUp()
// Verify that we cancelled the start animator in favor of the exit
// animator.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index cfd51e3..d0d348d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -23,7 +23,6 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -498,18 +497,14 @@
true /*shouldShowComplication*/);
mMainExecutor.runAllReady();
- final Runnable callback = mock(Runnable.class);
- mService.onWakeUp(callback);
- mMainExecutor.runAllReady();
- verify(mDreamOverlayContainerViewController).wakeUp(callback, mMainExecutor);
+ mService.onWakeUp();
+ verify(mDreamOverlayContainerViewController).wakeUp();
verify(mDreamOverlayCallbackController).onWakeUp();
}
@Test
public void testWakeUpBeforeStartDoesNothing() {
- final Runnable callback = mock(Runnable.class);
- mService.onWakeUp(callback);
- mMainExecutor.runAllReady();
- verify(mDreamOverlayContainerViewController, never()).wakeUp(callback, mMainExecutor);
+ mService.onWakeUp();
+ verify(mDreamOverlayContainerViewController, never()).wakeUp();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index f31ac00..8a422c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -21,6 +21,7 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -71,6 +72,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.settings.UserTracker;
@@ -105,6 +107,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.flow.Flow;
+
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
@@ -156,6 +161,8 @@
private @Mock CentralSurfaces mCentralSurfaces;
private @Mock UiEventLogger mUiEventLogger;
private @Mock SessionTracker mSessionTracker;
+ private @Mock CoroutineDispatcher mDispatcher;
+ private @Mock DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel;
private FakeFeatureFlags mFeatureFlags;
@@ -171,6 +178,8 @@
final ViewRootImpl testViewRoot = mock(ViewRootImpl.class);
when(testViewRoot.getView()).thenReturn(mock(View.class));
when(mStatusBarKeyguardViewManager.getViewRootImpl()).thenReturn(testViewRoot);
+ when(mDreamingToLockscreenTransitionViewModel.getDreamOverlayAlpha())
+ .thenReturn(mock(Flow.class));
mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(mContext,
mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
mConfigurationController, mViewMediator, mKeyguardBypassController,
@@ -186,6 +195,7 @@
}
@Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
public void onLockdown_showKeyguard_evenIfKeyguardIsNotEnabledExternally() {
// GIVEN keyguard is not enabled and isn't showing
mViewMediator.onSystemReady();
@@ -347,6 +357,42 @@
}
@Test
+ public void testBouncerPrompt_afterUserLockDown() {
+ // GIVEN biometrics enrolled
+ when(mUpdateMonitor.isUnlockingWithBiometricsPossible(anyInt())).thenReturn(true);
+
+ // WHEN user has locked down the device
+ KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker =
+ mock(KeyguardUpdateMonitor.StrongAuthTracker.class);
+ when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(strongAuthTracker);
+ when(strongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+ when(strongAuthTracker.getStrongAuthForUser(anyInt()))
+ .thenReturn(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+
+ // THEN the bouncer prompt reason should return PROMPT_REASON_USER_REQUEST
+ assertEquals(KeyguardSecurityView.PROMPT_REASON_USER_REQUEST,
+ mViewMediator.mViewMediatorCallback.getBouncerPromptReason());
+ }
+
+ @Test
+ public void testBouncerPrompt_afterUserLockDown_noBiometricsEnrolled() {
+ // GIVEN biometrics not enrolled
+ when(mUpdateMonitor.isUnlockingWithBiometricsPossible(anyInt())).thenReturn(false);
+
+ // WHEN user has locked down the device
+ KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker =
+ mock(KeyguardUpdateMonitor.StrongAuthTracker.class);
+ when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(strongAuthTracker);
+ when(strongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+ when(strongAuthTracker.getStrongAuthForUser(anyInt()))
+ .thenReturn(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+
+ // THEN the bouncer prompt reason should return the default prompt
+ assertEquals(KeyguardSecurityView.PROMPT_REASON_NONE,
+ mViewMediator.mViewMediatorCallback.getBouncerPromptReason());
+ }
+
+ @Test
public void testBouncerPrompt_nonStrongIdleTimeout() {
// GIVEN trust agents enabled and biometrics are enrolled
when(mUpdateMonitor.isTrustUsuallyManaged(anyInt())).thenReturn(true);
@@ -629,7 +675,9 @@
() -> mNotificationShadeWindowController,
() -> mActivityLaunchAnimator,
() -> mScrimController,
- mFeatureFlags);
+ mFeatureFlags,
+ mDispatcher,
+ () -> mDreamingToLockscreenTransitionViewModel);
mViewMediator.start();
mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
index 78a65a8..6447368 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
@@ -70,7 +70,10 @@
resourceTrimmer =
ResourceTrimmer(
keyguardInteractor,
- KeyguardTransitionInteractor(keyguardTransitionRepository),
+ KeyguardTransitionInteractor(
+ keyguardTransitionRepository,
+ testScope.backgroundScope
+ ),
globalWindowManager,
testScope.backgroundScope,
testDispatcher,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index e61620b..1090c15 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -215,7 +215,7 @@
)
keyguardTransitionRepository = FakeKeyguardTransitionRepository()
val keyguardTransitionInteractor =
- KeyguardTransitionInteractor(keyguardTransitionRepository)
+ KeyguardTransitionInteractor(keyguardTransitionRepository, testScope.backgroundScope)
return DeviceEntryFaceAuthRepositoryImpl(
mContext,
fmOverride,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index 6af1220..71e73cbd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -82,7 +82,8 @@
bouncerRepository = FakeKeyguardBouncerRepository()
faceAuthRepository = FakeDeviceEntryFaceAuthRepository()
keyguardTransitionRepository = FakeKeyguardTransitionRepository()
- keyguardTransitionInteractor = KeyguardTransitionInteractor(keyguardTransitionRepository)
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(keyguardTransitionRepository, testScope.backgroundScope)
underTest =
SystemUIKeyguardFaceAuthInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
index 5de24e4..f63be61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
@@ -292,7 +292,8 @@
scope = testScope.backgroundScope,
transitionInteractor =
KeyguardTransitionInteractor(
- repository = keyguardTransitionRepository,
+ keyguardTransitionRepository,
+ testScope.backgroundScope
),
repository = keyguardRepository,
logger = logger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
index d66e420..fa4941c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -27,11 +27,14 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.KeyguardState.OFF
+import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -46,11 +49,12 @@
private lateinit var underTest: KeyguardTransitionInteractor
private lateinit var repository: FakeKeyguardTransitionRepository
+ private val testScope = TestScope()
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
- underTest = KeyguardTransitionInteractor(repository)
+ underTest = KeyguardTransitionInteractor(repository, testScope.backgroundScope)
}
@Test
@@ -108,17 +112,17 @@
}
@Test
- fun keyguardStateTests() = runTest {
+ fun finishedKeyguardStateTests() = testScope.runTest {
val finishedSteps by collectValues(underTest.finishedKeyguardState)
-
+ runCurrent()
val steps = mutableListOf<TransitionStep>()
- steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED))
- steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING))
- steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED))
- steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED))
- steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING))
- steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED))
+ steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0f, STARTED))
+ steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0.5f, RUNNING))
+ steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 1f, FINISHED))
+ steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0f, STARTED))
+ steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0.9f, RUNNING))
+ steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 1f, FINISHED))
steps.add(TransitionStep(AOD, GONE, 1f, STARTED))
steps.forEach {
@@ -126,7 +130,29 @@
runCurrent()
}
- assertThat(finishedSteps).isEqualTo(listOf(LOCKSCREEN, AOD))
+ assertThat(finishedSteps).isEqualTo(listOf(LOCKSCREEN, PRIMARY_BOUNCER, AOD))
+ }
+
+ @Test
+ fun startedKeyguardStateTests() = testScope.runTest {
+ val finishedSteps by collectValues(underTest.startedKeyguardState)
+ runCurrent()
+ val steps = mutableListOf<TransitionStep>()
+
+ steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0f, STARTED))
+ steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0.5f, RUNNING))
+ steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 1f, FINISHED))
+ steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0f, STARTED))
+ steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0.9f, RUNNING))
+ steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 1f, FINISHED))
+ steps.add(TransitionStep(AOD, GONE, 1f, STARTED))
+
+ steps.forEach {
+ repository.sendTransitionStep(it)
+ runCurrent()
+ }
+
+ assertThat(finishedSteps).isEqualTo(listOf(OFF, PRIMARY_BOUNCER, AOD, GONE))
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 603f199..30dba23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -110,7 +110,8 @@
keyguardInteractor = createKeyguardInteractor(featureFlags),
shadeRepository = shadeRepository,
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
)
fromLockscreenTransitionInteractor.start()
@@ -119,7 +120,8 @@
scope = testScope,
keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
)
fromDreamingTransitionInteractor.start()
@@ -128,7 +130,8 @@
scope = testScope,
keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
)
fromAodTransitionInteractor.start()
@@ -137,7 +140,8 @@
scope = testScope,
keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
)
fromGoneTransitionInteractor.start()
@@ -146,7 +150,8 @@
scope = testScope,
keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
)
fromDozingTransitionInteractor.start()
@@ -155,7 +160,8 @@
scope = testScope,
keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
)
fromOccludedTransitionInteractor.start()
@@ -164,7 +170,8 @@
scope = testScope,
keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
)
fromAlternateBouncerTransitionInteractor.start()
@@ -173,48 +180,14 @@
scope = testScope,
keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardTransitionInteractor =
+ KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
keyguardSecurityModel = keyguardSecurityModel,
)
fromPrimaryBouncerTransitionInteractor.start()
}
@Test
- fun dreamingToLockscreen() =
- testScope.runTest {
- // GIVEN a device is dreaming
- keyguardRepository.setDreamingWithOverlay(true)
- keyguardRepository.setWakefulnessModel(startingToWake())
- runCurrent()
-
- // GIVEN a prior transition has run to DREAMING
- runTransition(KeyguardState.LOCKSCREEN, KeyguardState.DREAMING)
-
- // WHEN doze is complete
- keyguardRepository.setDozeTransitionModel(
- DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
- )
- // AND dreaming has stopped
- keyguardRepository.setDreamingWithOverlay(false)
- advanceUntilIdle()
- // AND then occluded has stopped
- keyguardRepository.setKeyguardOccluded(false)
- advanceUntilIdle()
-
- val info =
- withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
- }
- // THEN a transition to BOUNCER should occur
- assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.DREAMING)
- assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.animator).isNotNull()
-
- coroutineContext.cancelChildren()
- }
-
- @Test
fun lockscreenToPrimaryBouncerViaBouncerShowingCall() =
testScope.runTest {
// GIVEN a device that has at least woken up
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
index 4440946..08e99dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
@@ -29,6 +29,7 @@
import com.android.systemui.statusbar.LightRevealScrim
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
@@ -45,7 +46,7 @@
private val fakeLightRevealScrimRepository = FakeLightRevealScrimRepository()
private val keyguardTransitionInteractor =
- KeyguardTransitionInteractor(fakeKeyguardTransitionRepository)
+ KeyguardTransitionInteractor(fakeKeyguardTransitionRepository, TestScope().backgroundScope)
private lateinit var underTest: LightRevealScrimInteractor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
index cdd06ac..a341346 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
@@ -25,11 +25,12 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.util.mockito.mock
import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -42,13 +43,12 @@
class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
private lateinit var underTest: DreamingToLockscreenTransitionViewModel
private lateinit var repository: FakeKeyguardTransitionRepository
- private lateinit var transitionAnimation: KeyguardTransitionAnimationFlow
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
- val interactor = KeyguardTransitionInteractor(repository)
- underTest = DreamingToLockscreenTransitionViewModel(interactor)
+ val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
+ underTest = DreamingToLockscreenTransitionViewModel(interactor, mock())
}
@Test
@@ -60,17 +60,15 @@
val job =
underTest.dreamOverlayTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
- // Should start running here...
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
repository.sendTransitionStep(step(0f))
repository.sendTransitionStep(step(0.3f))
repository.sendTransitionStep(step(0.5f))
repository.sendTransitionStep(step(0.6f))
- // ...up to here
repository.sendTransitionStep(step(0.8f))
repository.sendTransitionStep(step(1f))
- assertThat(values.size).isEqualTo(5)
+ assertThat(values.size).isEqualTo(7)
values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) }
job.cancel()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
index 40511a0..694539b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt
@@ -29,6 +29,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -45,7 +46,7 @@
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
- val interactor = KeyguardTransitionInteractor(repository)
+ val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest = GoneToDreamingTransitionViewModel(interactor)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 73fe380..b6368cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -219,6 +219,7 @@
transitionInteractor =
KeyguardTransitionInteractor(
repository = FakeKeyguardTransitionRepository(),
+ scope = testScope.backgroundScope
),
repository = repository,
logger = UiEventLoggerFake(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
index c98058d..ea17751 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt
@@ -29,6 +29,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -45,7 +46,7 @@
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
- val interactor = KeyguardTransitionInteractor(repository)
+ val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest = LockscreenToDreamingTransitionViewModel(interactor)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
index 031b7fb..bf56a98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt
@@ -29,6 +29,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -45,7 +46,7 @@
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
- val interactor = KeyguardTransitionInteractor(repository)
+ val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest = LockscreenToOccludedTransitionViewModel(interactor)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
index c7ff882..34da26e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
@@ -29,6 +29,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -45,7 +46,7 @@
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
- val interactor = KeyguardTransitionInteractor(repository)
+ val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest = OccludedToLockscreenTransitionViewModel(interactor)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
index db251a0..65b2ef7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -33,6 +33,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -54,7 +55,7 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
repository = FakeKeyguardTransitionRepository()
- val interactor = KeyguardTransitionInteractor(repository)
+ val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest =
PrimaryBouncerToGoneTransitionViewModel(
interactor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index 07f7c15..2aff90c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -63,6 +63,7 @@
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -146,7 +147,7 @@
debugLogger,
mediaFlags,
keyguardUpdateMonitor,
- KeyguardTransitionInteractor(repository = transitionRepository),
+ KeyguardTransitionInteractor(transitionRepository, TestScope().backgroundScope),
)
verify(configurationController).addCallback(capture(configListener))
verify(mediaDataManager).addListener(capture(listener))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt
index 19f9960..9e54224 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/multishade/domain/interactor/MultiShadeMotionEventInteractorTest.kt
@@ -99,6 +99,7 @@
keyguardTransitionInteractor =
KeyguardTransitionInteractor(
repository = keyguardTransitionRepository,
+ scope = testScope.backgroundScope
),
falsingManager = falsingManager,
shadeController = shadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 16277de..3995e71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -103,8 +103,8 @@
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
- @Mock
- private lateinit var unfoldTransitionProgressProvider: Optional<UnfoldTransitionProgressProvider>
+ @Mock private lateinit var unfoldTransitionProgressProvider:
+ Optional<UnfoldTransitionProgressProvider>
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock
lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
@@ -184,6 +184,7 @@
keyguardTransitionInteractor =
KeyguardTransitionInteractor(
repository = FakeKeyguardTransitionRepository(),
+ scope = testScope.backgroundScope
),
falsingManager = FalsingManagerFake(),
shadeController = shadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 16af208..fe95742 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -59,6 +59,7 @@
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.test.TestScope
@@ -72,7 +73,6 @@
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-import java.util.Optional
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidTestingRunner::class)
@@ -106,7 +106,8 @@
@Mock
private lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
@Mock
- private lateinit var unfoldTransitionProgressProvider: Optional<UnfoldTransitionProgressProvider>
+ private lateinit var unfoldTransitionProgressProvider:
+ Optional<UnfoldTransitionProgressProvider>
@Mock private lateinit var notificationInsetsController: NotificationInsetsController
@Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock
@@ -195,6 +196,7 @@
keyguardTransitionInteractor =
KeyguardTransitionInteractor(
repository = FakeKeyguardTransitionRepository(),
+ scope = testScope.backgroundScope
),
falsingManager = FalsingManagerFake(),
shadeController = shadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
index d421aca..b028f1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QsBatteryModeControllerTest.kt
@@ -63,36 +63,40 @@
@Test
fun returnsMODE_ESTIMATEforQsWithCenterCutout() {
+ // TODO (b/282044659): revert this test to previous behavior
assertThat(controller.getBatteryMode(CENTER_TOP_CUTOUT, QS_END_FRAME.nextFrameToFraction()))
- .isEqualTo(BatteryMeterView.MODE_ESTIMATE)
+ .isEqualTo(BatteryMeterView.MODE_ON)
}
@Test
fun returnsMODE_ONforQqsWithCornerCutout() {
whenever(insetsProvider.currentRotationHasCornerCutout()).thenReturn(true)
+ // TODO (b/282044659): revert this test to previous behavior
assertThat(
controller.getBatteryMode(CENTER_TOP_CUTOUT, QQS_START_FRAME.prevFrameToFraction())
)
- .isEqualTo(BatteryMeterView.MODE_ESTIMATE)
+ .isEqualTo(BatteryMeterView.MODE_ON)
}
@Test
fun returnsMODE_ESTIMATEforQsWithCornerCutout() {
whenever(insetsProvider.currentRotationHasCornerCutout()).thenReturn(true)
+ // TODO (b/282044659): revert this test to previous behavior
assertThat(controller.getBatteryMode(CENTER_TOP_CUTOUT, QS_END_FRAME.nextFrameToFraction()))
- .isEqualTo(BatteryMeterView.MODE_ESTIMATE)
+ .isEqualTo(BatteryMeterView.MODE_ON)
}
@Test
fun returnsNullInBetween() {
+ // TODO (b/282044659): revert this test to previous behavior
assertThat(
controller.getBatteryMode(CENTER_TOP_CUTOUT, QQS_START_FRAME.nextFrameToFraction())
)
- .isNull()
+ .isEqualTo(BatteryMeterView.MODE_ON)
assertThat(controller.getBatteryMode(CENTER_TOP_CUTOUT, QS_END_FRAME.prevFrameToFraction()))
- .isNull()
+ .isEqualTo(BatteryMeterView.MODE_ON)
}
private fun Int.prevFrameToFraction(): Float = (this - 1) / MOTION_LAYOUT_MAX_FRAME.toFloat()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 8062272..7702630 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -350,7 +350,9 @@
// For the Shade to animate during the Back gesture, we must enable the animation flag.
mFeatureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, true);
mFeatureFlags.set(Flags.LIGHT_REVEAL_MIGRATION, true);
+ // Turn AOD on and toggle feature flag for jank fixes
mFeatureFlags.set(Flags.ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD, true);
+ when(mDozeParameters.getAlwaysOn()).thenReturn(true);
IThermalService thermalService = mock(IThermalService.class);
mPowerManager = new PowerManager(mContext, mPowerManagerService, thermalService,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index c8c24a7..6301fa0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -47,7 +47,8 @@
testScope = TestScope(UnconfinedTestDispatcher())
keyguardTransitionRepository = FakeKeyguardTransitionRepository()
- val interactor = KeyguardTransitionInteractor(keyguardTransitionRepository)
+ val interactor =
+ KeyguardTransitionInteractor(keyguardTransitionRepository, testScope.backgroundScope)
underTest = CollapsedStatusBarViewModelImpl(interactor, testScope.backgroundScope)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
index 67727ae..d1c38f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
@@ -77,6 +77,7 @@
)
whenever(controller.users).thenAnswer { users }
+ whenever(controller.isUserSwitcherEnabled).thenReturn(true)
underTest =
object : BaseUserSwitcherAdapter(controller) {
@@ -162,6 +163,19 @@
}
@Test
+ fun count_onlyShowsCurrentUserWhenMultiUserDisabled() {
+ whenever(controller.isUserSwitcherEnabled).thenReturn(false)
+ assertThat(underTest.count).isEqualTo(1)
+ assertThat(underTest.getItem(0).isCurrent).isTrue()
+ }
+
+ @Test
+ fun count_doesNotIgnoreAllOtherUsersWhenMultiUserEnabled() {
+ whenever(controller.isUserSwitcherEnabled).thenReturn(true)
+ assertThat(underTest.count).isEqualTo(users.size)
+ }
+
+ @Test
fun getItem() {
assertThat((0 until underTest.count).map { position -> underTest.getItem(position) })
.isEqualTo(users)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
index 8290dab..1ab62d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
@@ -29,6 +29,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.qs.tiles.UserDetailItemView
import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.util.mockito.whenever
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
@@ -68,6 +69,8 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
+ whenever(userSwitcherController.isUserSwitcherEnabled).thenReturn(true)
+
mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, layoutInflater)
`when`(layoutInflater.inflate(anyInt(), any(ViewGroup::class.java), anyBoolean()))
.thenReturn(inflatedUserDetailItemView)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
index fbc2381..61e5b5f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
@@ -79,6 +79,10 @@
return _userSwitcherSettings.value.isSimpleUserSwitcher
}
+ override fun isUserSwitcherEnabled(): Boolean {
+ return _userSwitcherSettings.value.isUserSwitcherEnabled
+ }
+
fun setUserInfos(infos: List<UserInfo>) {
_userInfos.value = infos
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0916960..a7db663 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -14449,6 +14449,8 @@
&& !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
Slog.w(TAG, "Skipping broadcast of " + intent
+ ": user " + userId + " and its parent (if any) are stopped");
+ scheduleCanceledResultTo(resultToApp, resultTo, intent, userId,
+ brOptions, callingUid, callerPackage);
return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
}
}
@@ -14520,6 +14522,8 @@
isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception", e);
+ scheduleCanceledResultTo(resultToApp, resultTo, intent,
+ userId, brOptions, callingUid, callerPackage);
return ActivityManager.BROADCAST_SUCCESS;
}
@@ -14753,6 +14757,8 @@
if (aInfo == null) {
Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:"
+ " ssp=" + ssp + " data=" + data);
+ scheduleCanceledResultTo(resultToApp, resultTo, intent,
+ userId, brOptions, callingUid, callerPackage);
return ActivityManager.BROADCAST_SUCCESS;
}
updateAssociationForApp(aInfo);
@@ -14838,6 +14844,8 @@
// Apps should now be using ShortcutManager.pinRequestShortcut().
Log.w(TAG, "Broadcast " + action
+ " no longer supported. It will not be delivered.");
+ scheduleCanceledResultTo(resultToApp, resultTo, intent,
+ userId, brOptions, callingUid, callerPackage);
return ActivityManager.BROADCAST_SUCCESS;
case Intent.ACTION_PRE_BOOT_COMPLETED:
timeoutExempt = true;
@@ -14845,6 +14853,8 @@
case Intent.ACTION_CLOSE_SYSTEM_DIALOGS:
if (!mAtmInternal.checkCanCloseSystemDialogs(callingPid, callingUid,
callerPackage)) {
+ scheduleCanceledResultTo(resultToApp, resultTo, intent,
+ userId, brOptions, callingUid, callerPackage);
// Returning success seems to be the pattern here
return ActivityManager.BROADCAST_SUCCESS;
}
@@ -14879,6 +14889,8 @@
if (requiredPermissions != null && requiredPermissions.length > 0) {
Slog.w(TAG, "Can't broadcast sticky intent " + intent
+ " and enforce permissions " + Arrays.toString(requiredPermissions));
+ scheduleCanceledResultTo(resultToApp, resultTo, intent,
+ userId, brOptions, callingUid, callerPackage);
return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
}
if (intent.getComponent() != null) {
@@ -15130,6 +15142,33 @@
}
@GuardedBy("this")
+ private void scheduleCanceledResultTo(ProcessRecord resultToApp, IIntentReceiver resultTo,
+ Intent intent, int userId, BroadcastOptions options, int callingUid,
+ String callingPackage) {
+ if (resultTo == null) {
+ return;
+ }
+ final ProcessRecord app = resultToApp;
+ final IApplicationThread thread = (app != null) ? app.getOnewayThread() : null;
+ if (thread != null) {
+ try {
+ final boolean shareIdentity = (options != null && options.isShareIdentityEnabled());
+ thread.scheduleRegisteredReceiver(
+ resultTo, intent, Activity.RESULT_CANCELED, null, null,
+ false, false, true, userId, app.mState.getReportedProcState(),
+ shareIdentity ? callingUid : Process.INVALID_UID,
+ shareIdentity ? callingPackage : null);
+ } catch (RemoteException e) {
+ final String msg = "Failed to schedule result of " + intent + " via "
+ + app + ": " + e;
+ app.killLocked("Can't schedule resultTo", ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.SUBREASON_UNDELIVERED_BROADCAST, true);
+ Slog.d(TAG, msg);
+ }
+ }
+ }
+
+ @GuardedBy("this")
private int getRealProcessStateLocked(ProcessRecord app, int pid) {
if (app == null) {
synchronized (mPidsSelfLocked) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index ba8a1b9..569f55f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -928,8 +928,8 @@
final int result = mInterface.broadcastIntentWithFeature(null, null, intent, null,
receiver, 0, null, null, requiredPermissions, null, null,
android.app.AppOpsManager.OP_NONE, bundle, true, false, mUserId);
- Slogf.i(TAG, "Broadcasted %s: " + result, intent);
- if (!mAsync) {
+ Slogf.i(TAG, "Enqueued broadcast %s: " + result, intent);
+ if (result == ActivityManager.BROADCAST_SUCCESS && !mAsync) {
receiver.waitForFinish();
}
return 0;
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 33e21f1..03d1fbb 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -1608,11 +1608,15 @@
refreshProcessQueuesLocked(uid);
}
}
+ }, ActivityManager.UID_OBSERVER_PROCSTATE,
+ ActivityManager.PROCESS_STATE_TOP, "android");
+ mService.registerUidObserver(new UidObserver() {
@Override
- public void onUidCachedChanged(int uid, boolean cached) {
+ public void onUidStateChanged(int uid, int procState, long procStateSeq,
+ int capability) {
synchronized (mService) {
- if (cached) {
+ if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
mUidCached.put(uid, true);
} else {
mUidCached.delete(uid);
@@ -1620,8 +1624,8 @@
refreshProcessQueuesLocked(uid);
}
}
- }, ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_CACHED,
- ActivityManager.PROCESS_STATE_TOP, "android");
+ }, ActivityManager.UID_OBSERVER_PROCSTATE,
+ ActivityManager.PROCESS_STATE_LAST_ACTIVITY, "android");
// Kick off periodic health checks
mLocalHandler.sendEmptyMessage(MSG_CHECK_HEALTH);
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 7773190..eccff2a 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -123,7 +123,14 @@
"freeze_debounce_timeout";
@VisibleForTesting static final String KEY_FREEZER_EXEMPT_INST_PKG =
"freeze_exempt_inst_pkg";
-
+ @VisibleForTesting static final String KEY_FREEZER_BINDER_ENABLED =
+ "freeze_binder_enabled";
+ @VisibleForTesting static final String KEY_FREEZER_BINDER_DIVISOR =
+ "freeze_binder_divisor";
+ @VisibleForTesting static final String KEY_FREEZER_BINDER_OFFSET =
+ "freeze_binder_offset";
+ @VisibleForTesting static final String KEY_FREEZER_BINDER_THRESHOLD =
+ "freeze_binder_threshold";
static final int UNFREEZE_REASON_NONE =
FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_NONE;
@@ -237,8 +244,8 @@
@VisibleForTesting static final boolean ENABLE_FILE_COMPACT = false;
// Defaults for phenotype flags.
- @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = true;
- @VisibleForTesting static final Boolean DEFAULT_USE_FREEZER = true;
+ @VisibleForTesting static final boolean DEFAULT_USE_COMPACTION = true;
+ @VisibleForTesting static final boolean DEFAULT_USE_FREEZER = true;
@VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_1 = 5_000;
@VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000;
@VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500;
@@ -257,7 +264,11 @@
@VisibleForTesting static final String DEFAULT_COMPACT_PROC_STATE_THROTTLE =
String.valueOf(ActivityManager.PROCESS_STATE_RECEIVER);
@VisibleForTesting static final long DEFAULT_FREEZER_DEBOUNCE_TIMEOUT = 10_000L;
- @VisibleForTesting static final Boolean DEFAULT_FREEZER_EXEMPT_INST_PKG = true;
+ @VisibleForTesting static final boolean DEFAULT_FREEZER_EXEMPT_INST_PKG = true;
+ @VisibleForTesting static final boolean DEFAULT_FREEZER_BINDER_ENABLED = true;
+ @VisibleForTesting static final long DEFAULT_FREEZER_BINDER_DIVISOR = 4;
+ @VisibleForTesting static final int DEFAULT_FREEZER_BINDER_OFFSET = 500;
+ @VisibleForTesting static final long DEFAULT_FREEZER_BINDER_THRESHOLD = 1_000;
@VisibleForTesting static final Uri CACHED_APP_FREEZER_ENABLED_URI = Settings.Global.getUriFor(
Settings.Global.CACHED_APPS_FREEZER_ENABLED);
@@ -393,6 +404,11 @@
updateFreezerDebounceTimeout();
} else if (KEY_FREEZER_EXEMPT_INST_PKG.equals(name)) {
updateFreezerExemptInstPkg();
+ } else if (KEY_FREEZER_BINDER_ENABLED.equals(name)
+ || KEY_FREEZER_BINDER_DIVISOR.equals(name)
+ || KEY_FREEZER_BINDER_THRESHOLD.equals(name)
+ || KEY_FREEZER_BINDER_OFFSET.equals(name)) {
+ updateFreezerBinderState();
}
}
}
@@ -455,6 +471,16 @@
@GuardedBy("mPhenotypeFlagLock")
@VisibleForTesting final Set<Integer> mProcStateThrottle;
+ @GuardedBy("mPhenotypeFlagLock")
+ @VisibleForTesting volatile boolean mFreezerBinderEnabled = DEFAULT_FREEZER_BINDER_ENABLED;
+ @GuardedBy("mPhenotypeFlagLock")
+ @VisibleForTesting volatile long mFreezerBinderDivisor = DEFAULT_FREEZER_BINDER_DIVISOR;
+ @GuardedBy("mPhenotypeFlagLock")
+ @VisibleForTesting volatile int mFreezerBinderOffset = DEFAULT_FREEZER_BINDER_OFFSET;
+ @GuardedBy("mPhenotypeFlagLock")
+ @VisibleForTesting volatile long mFreezerBinderThreshold = DEFAULT_FREEZER_BINDER_THRESHOLD;
+
+
// Handler on which compaction runs.
@VisibleForTesting
Handler mCompactionHandler;
@@ -759,6 +785,10 @@
pw.println(" " + KEY_FREEZER_STATSD_SAMPLE_RATE + "=" + mFreezerStatsdSampleRate);
pw.println(" " + KEY_FREEZER_DEBOUNCE_TIMEOUT + "=" + mFreezerDebounceTimeout);
pw.println(" " + KEY_FREEZER_EXEMPT_INST_PKG + "=" + mFreezerExemptInstPkg);
+ pw.println(" " + KEY_FREEZER_BINDER_ENABLED + "=" + mFreezerBinderEnabled);
+ pw.println(" " + KEY_FREEZER_BINDER_THRESHOLD + "=" + mFreezerBinderThreshold);
+ pw.println(" " + KEY_FREEZER_BINDER_DIVISOR + "=" + mFreezerBinderDivisor);
+ pw.println(" " + KEY_FREEZER_BINDER_OFFSET + "=" + mFreezerBinderOffset);
synchronized (mProcLock) {
int size = mFrozenProcesses.size();
pw.println(" Apps frozen: " + size);
@@ -1264,6 +1294,26 @@
Slog.d(TAG_AM, "Freezer exemption set to " + mFreezerExemptInstPkg);
}
+ @GuardedBy("mPhenotypeFlagLock")
+ private void updateFreezerBinderState() {
+ mFreezerBinderEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ KEY_FREEZER_BINDER_ENABLED, DEFAULT_FREEZER_BINDER_ENABLED);
+ mFreezerBinderDivisor = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ KEY_FREEZER_BINDER_DIVISOR, DEFAULT_FREEZER_BINDER_DIVISOR);
+ mFreezerBinderOffset = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ KEY_FREEZER_BINDER_OFFSET, DEFAULT_FREEZER_BINDER_OFFSET);
+ mFreezerBinderThreshold = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ KEY_FREEZER_BINDER_THRESHOLD, DEFAULT_FREEZER_BINDER_THRESHOLD);
+ Slog.d(TAG_AM, "Freezer binder state set to enabled=" + mFreezerBinderEnabled
+ + ", divisor=" + mFreezerBinderDivisor
+ + ", offset=" + mFreezerBinderOffset
+ + ", threshold=" + mFreezerBinderThreshold);
+ }
+
private boolean parseProcStateThrottle(String procStateThrottleString) {
String[] procStates = TextUtils.split(procStateThrottleString, ",");
mProcStateThrottle.clear();
@@ -1352,6 +1402,7 @@
}
}
}
+ app.mOptRecord.setLastUsedTimeout(delayMillis);
mFreezeHandler.sendMessageDelayed(
mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app),
delayMillis);
@@ -1525,10 +1576,14 @@
opt.setPendingFreeze(false);
}
- UidRecord uidRec = app.getUidRecord();
- if (uidRec != null && uidRec.isFrozen()) {
- uidRec.setFrozen(false);
- postUidFrozenMessage(uidRec.getUid(), false);
+ final UidRecord uidRec = app.getUidRecord();
+ if (uidRec != null) {
+ final boolean isFrozen = uidRec.getNumOfProcs() > 1
+ && uidRec.areAllProcessesFrozen(app);
+ if (isFrozen != uidRec.isFrozen()) {
+ uidRec.setFrozen(isFrozen);
+ postUidFrozenMessage(uidRec.getUid(), isFrozen);
+ }
}
mFrozenProcesses.delete(app.getPid());
@@ -2117,12 +2172,54 @@
}
@GuardedBy({"mAm", "mProcLock"})
- private void rescheduleFreeze(final ProcessRecord proc, final String reason,
- @UnfreezeReason int reasonCode) {
+ private void handleBinderFreezerFailure(final ProcessRecord proc, final String reason) {
+ if (!mFreezerBinderEnabled) {
+ // Just reschedule indefinitely.
+ unfreezeAppLSP(proc, UNFREEZE_REASON_BINDER_TXNS);
+ freezeAppAsyncLSP(proc);
+ return;
+ }
+ /*
+ * This handles the case where a process couldn't be frozen due to pending binder
+ * transactions. In order to prevent apps from avoiding the freezer by spamming binder
+ * transactions, there is an exponential decrease in freezer retry times plus a random
+ * offset per attempt to avoid phase issues. Once the last-attempted timeout is below a
+ * threshold, we assume that the app is spamming binder calls and can never be frozen,
+ * and we will then crash the app.
+ */
+ if (proc.mOptRecord.getLastUsedTimeout() <= mFreezerBinderThreshold) {
+ // We've given the app plenty of chances, assume broken. Time to die.
+ Slog.d(TAG_AM, "Kill app due to repeated failure to freeze binder: "
+ + proc.getPid() + " " + proc.processName);
+ mAm.mHandler.post(() -> {
+ synchronized (mAm) {
+ // Crash regardless of procstate in case the app has found another way
+ // to abuse oom_adj
+ if (proc.getThread() == null) {
+ return;
+ }
+ proc.killLocked("excessive binder traffic during cached",
+ ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
+ ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU,
+ true);
+ }
+ });
+ return;
+ }
+
+ long timeout = proc.mOptRecord.getLastUsedTimeout() / mFreezerBinderDivisor;
+ // range is [-mFreezerBinderOffset, +mFreezerBinderOffset]
+ int offset = mRandom.nextInt(mFreezerBinderOffset * 2) - mFreezerBinderOffset;
+ timeout = Math.max(timeout + offset, mFreezerBinderThreshold);
+
Slog.d(TAG_AM, "Reschedule freeze for process " + proc.getPid()
- + " " + proc.processName + " (" + reason + ")");
- unfreezeAppLSP(proc, reasonCode);
- freezeAppAsyncLSP(proc);
+ + " " + proc.processName + " (" + reason + "), timeout=" + timeout);
+ Trace.instantForTrack(Trace.TRACE_TAG_ACTIVITY_MANAGER, ATRACE_FREEZER_TRACK,
+ "Reschedule freeze " + proc.processName + ":" + proc.getPid()
+ + " timeout=" + timeout + ", reason=" + reason);
+
+ unfreezeAppLSP(proc, UNFREEZE_REASON_BINDER_TXNS);
+ freezeAppAsyncLSP(proc, timeout);
}
/**
@@ -2169,7 +2266,7 @@
// transactions that might be pending.
try {
if (freezeBinder(pid, true, FREEZE_BINDER_TIMEOUT_MS) != 0) {
- rescheduleFreeze(proc, "outstanding txns", UNFREEZE_REASON_BINDER_TXNS);
+ handleBinderFreezerFailure(proc, "outstanding txns");
return;
}
} catch (RuntimeException e) {
@@ -2230,7 +2327,7 @@
if ((freezeInfo & TXNS_PENDING_WHILE_FROZEN) != 0) {
synchronized (mProcLock) {
- rescheduleFreeze(proc, "new pending txns", UNFREEZE_REASON_BINDER_TXNS);
+ handleBinderFreezerFailure(proc, "new pending txns");
}
return;
}
diff --git a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
index ffe5a6e..f5c5ea8 100644
--- a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
+++ b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
@@ -127,6 +127,12 @@
@GuardedBy("mProcLock")
private @UptimeMillisLong long mEarliestFreezableTimeMillis;
+ /**
+ * This is the most recently used timeout for freezing the app in millis
+ */
+ @GuardedBy("mProcLock")
+ private long mLastUsedTimeout;
+
@GuardedBy("mProcLock")
long getLastCompactTime() {
return mLastCompactTime;
@@ -282,6 +288,16 @@
}
@GuardedBy("mProcLock")
+ long getLastUsedTimeout() {
+ return mLastUsedTimeout;
+ }
+
+ @GuardedBy("mProcLock")
+ void setLastUsedTimeout(long lastUsedTimeout) {
+ mLastUsedTimeout = lastUsedTimeout;
+ }
+
+ @GuardedBy("mProcLock")
boolean isFreezeExempt() {
return mFreezeExempt;
}
diff --git a/services/core/java/com/android/server/am/StackTracesDumpHelper.java b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
index af99684..cf69b53 100644
--- a/services/core/java/com/android/server/am/StackTracesDumpHelper.java
+++ b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
@@ -229,7 +229,7 @@
firstPidEnd = new File(tracesFile).length();
}
// Append the Durations/latency comma separated array after the first PID.
- if (latencyTracker != null) {
+ if (firstPidTempDumpCopied && latencyTracker != null) {
appendtoANRFile(tracesFile,
latencyTracker.dumpAsCommaSeparatedArrayWithHeader());
}
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 993088e..4329afc 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -345,21 +345,32 @@
}
/**
+ * Check whether all processes in the Uid are frozen.
+ *
+ * @param excluding Skip this process record during the check.
* @return true if all processes in the Uid are frozen, false otherwise.
*/
@GuardedBy(anyOf = {"mService", "mProcLock"})
- public boolean areAllProcessesFrozen() {
+ public boolean areAllProcessesFrozen(ProcessRecord excluding) {
for (int i = mProcRecords.size() - 1; i >= 0; i--) {
final ProcessRecord app = mProcRecords.valueAt(i);
final ProcessCachedOptimizerRecord opt = app.mOptRecord;
- if (!opt.isFrozen()) {
+ if (excluding != app && !opt.isFrozen()) {
return false;
}
}
return true;
}
+ /**
+ * @return true if all processes in the Uid are frozen, false otherwise.
+ */
+ @GuardedBy(anyOf = {"mService", "mProcLock"})
+ public boolean areAllProcessesFrozen() {
+ return areAllProcessesFrozen(null);
+ }
+
@GuardedBy(anyOf = {"mService", "mProcLock"})
public void setFrozen(boolean frozen) {
mUidIsFrozen = frozen;
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 4e7865c..2d74564 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -88,8 +88,6 @@
UserSwitchingDialog(Context context, UserInfo oldUser, UserInfo newUser,
String switchingFromSystemUserMessage, String switchingToSystemUserMessage,
WindowManagerService windowManager) {
- // TODO(b/278857848): Make full screen user switcher cover top part of the screen as well.
- // This problem is seen only on phones, it works fine on tablets.
super(context, R.style.Theme_Material_NoActionBar_Fullscreen);
mContext = context;
@@ -112,9 +110,12 @@
final WindowManager.LayoutParams attrs = window.getAttributes();
attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR |
WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+ attrs.layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
window.setAttributes(attrs);
window.setBackgroundDrawableResource(android.R.color.transparent);
window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+ window.setDecorFitsSystemWindows(false);
}
void inflateContent() {
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 9fc0038..50ffbcb9 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -812,8 +812,7 @@
return false;
}
final int reqUsage = requester.getAudioAttributes().getUsage();
- if ((reqUsage == AudioAttributes.USAGE_ASSISTANT)
- || (reqUsage == AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)) {
+ if (reqUsage == AudioAttributes.USAGE_ASSISTANT) {
return true;
}
return false;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d29d9c8..488745c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -8718,13 +8718,7 @@
ToastRecord lastToast = mToastQueue.remove(index);
- mWindowManagerInternal.removeWindowToken(lastToast.windowToken, false /* removeWindows */,
- lastToast.displayId);
- // We passed 'false' for 'removeWindows' so that the client has time to stop
- // rendering (as hide above is a one-way message), otherwise we could crash
- // a client which was actively using a surface made from the token. However
- // we need to schedule a timeout to make sure the token is eventually killed
- // one way or another.
+ // We need to schedule a timeout to make sure the token is eventually killed
scheduleKillTokenTimeout(lastToast);
keepProcessAliveForToastIfNeededLocked(record.pid);
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index abfc1d7..78f1fa6 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -4311,7 +4311,12 @@
if (Process.isIsolatedUid(uid)
&& mPermissionManager.getHotwordDetectionServiceProvider() != null
&& uid == mPermissionManager.getHotwordDetectionServiceProvider().getUid()) {
- uid = getIsolatedOwner(uid);
+ try {
+ uid = getIsolatedOwner(uid);
+ } catch (IllegalStateException e) {
+ // If the owner uid doesn't exist, just use the current uid
+ Slog.wtf(TAG, "Expected isolated uid " + uid + " to have an owner", e);
+ }
}
final int callingUserId = UserHandle.getUserId(callingUid);
final int appId = UserHandle.getAppId(uid);
@@ -4352,7 +4357,12 @@
if (Process.isIsolatedUid(uid)
&& mPermissionManager.getHotwordDetectionServiceProvider() != null
&& uid == mPermissionManager.getHotwordDetectionServiceProvider().getUid()) {
- uid = getIsolatedOwner(uid);
+ try {
+ uid = getIsolatedOwner(uid);
+ } catch (IllegalStateException e) {
+ // If the owner uid doesn't exist, just use the current uid
+ Slog.wtf(TAG, "Expected isolated uid " + uid + " to have an owner", e);
+ }
}
final int appId = UserHandle.getAppId(uid);
final Object obj = mSettings.getSettingBase(appId);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 9e9b344..e31b53c 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -3293,7 +3293,7 @@
WallpaperData wallpaper;
synchronized (mLock) {
- Slog.v(TAG, "setWallpaperComponent name=" + name);
+ Slog.v(TAG, "setWallpaperComponent name=" + name + ", which=" + which);
wallpaper = mWallpaperMap.get(userId);
if (wallpaper == null) {
throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
@@ -3324,7 +3324,11 @@
wallpaper.mWhich = which;
wallpaper.fromForegroundApp = isFromForegroundApp(callingPackage);
boolean same = changingToSame(name, wallpaper);
- if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
+
+ // force rebind when reapplying a system-only wallpaper to system+lock
+ boolean forceRebind = same && mLockWallpaperMap.get(userId) != null
+ && which == (FLAG_SYSTEM | FLAG_LOCK);
+ if (bindWallpaperComponentLocked(name, forceRebind, true, wallpaper, null)) {
if (!same) {
wallpaper.primaryColors = null;
} else {
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 8660bec..89f044b 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -178,6 +178,10 @@
mSurfaceAnimatorStarter = surfaceAnimatorStarter;
}
+ WindowContainer<?> getHost() {
+ return mHost;
+ }
+
private SurfaceControl makeDimLayer() {
return mHost.makeChildSurface(null)
.setParent(mHost.getSurfaceControl())
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 9f59f5a..f81e5d4 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -790,7 +790,8 @@
// If SystemUI is dragging for recents, we want to reset the dim state so any dim layer
// on the display level fades out.
- if (forAllTasks(task -> !task.canAffectSystemUiFlags())) {
+ if (!mTransitionController.isShellTransitionsEnabled()
+ && forAllTasks(task -> !task.canAffectSystemUiFlags())) {
mDimmer.resetDimStates();
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 65771d1..95c953a 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2368,7 +2368,8 @@
// We need to force the consumption of the system bars if they are force shown or if they
// are controlled by a remote insets controller.
mForceConsumeSystemBars = mForceShowSystemBars
- || mDisplayContent.getInsetsPolicy().remoteInsetsControllerControlsSystemBars(win);
+ || getInsetsPolicy().remoteInsetsControllerControlsSystemBars(win)
+ || getInsetsPolicy().forcesShowingNavigationBars(win);
mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
final boolean topAppHidesStatusBar = topAppHidesSystemBar(Type.statusBars());
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index ddf96c5..daa823c 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -567,8 +567,7 @@
return focusedWin;
}
}
- if (mPolicy.isForceShowNavigationBarEnabled() && focusedWin != null
- && focusedWin.getActivityType() == ACTIVITY_TYPE_STANDARD) {
+ if (forcesShowingNavigationBars(focusedWin)) {
// When "force show navigation bar" is enabled, it means both force visible is true, and
// we are in 3-button navigation. In this mode, the navigation bar is forcibly shown
// when activity type is ACTIVITY_TYPE_STANDARD which means Launcher or Recent could
@@ -604,6 +603,11 @@
return focusedWin;
}
+ boolean forcesShowingNavigationBars(WindowState win) {
+ return mPolicy.isForceShowNavigationBarEnabled() && win != null
+ && win.getActivityType() == ACTIVITY_TYPE_STANDARD;
+ }
+
/**
* Determines whether the remote insets controller should take control of system bars for all
* windows.
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index aad1225..3d9edca 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -397,6 +397,28 @@
return false;
}
+ boolean canApplyDim(@NonNull Task task) {
+ if (mTransientLaunches == null) return true;
+ final Dimmer dimmer = task.getDimmer();
+ final WindowContainer<?> dimmerHost = dimmer != null ? dimmer.getHost() : null;
+ if (dimmerHost == null) return false;
+ if (isInTransientHide(dimmerHost)) {
+ // The layer of dimmer is inside transient-hide task, then allow to dim.
+ return true;
+ }
+ // The dimmer host of a translucent task can be a display, then it is not in transient-hide.
+ for (int i = mTransientLaunches.size() - 1; i >= 0; --i) {
+ // The transient task is usually the task of recents/home activity.
+ final Task transientTask = mTransientLaunches.keyAt(i).getTask();
+ if (transientTask != null && transientTask.canAffectSystemUiFlags()) {
+ // It usually means that the recents animation has moved the transient-hide task
+ // an noticeable distance, then the display level dimmer should not show.
+ return false;
+ }
+ }
+ return true;
+ }
+
boolean hasTransientLaunch() {
return mTransientLaunches != null && !mTransientLaunches.isEmpty();
}
@@ -1224,6 +1246,16 @@
mController.mAtm.mRootWindowContainer.getDisplayContent(mRecentsDisplayId);
dc.getInputMonitor().setActiveRecents(null /* activity */, null /* layer */);
}
+ if (mTransientLaunches != null) {
+ for (int i = mTransientLaunches.size() - 1; i >= 0; --i) {
+ // Reset the ability of controlling SystemUi which might be changed by
+ // setTransientLaunch or setRecentsAppBehindSystemBars.
+ final Task task = mTransientLaunches.keyAt(i).getTask();
+ if (task != null) {
+ task.setCanAffectSystemUiFlags(true);
+ }
+ }
+ }
for (int i = 0; i < mTargetDisplays.size(); ++i) {
final DisplayContent dc = mTargetDisplays.get(i);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 359b353..a539a48 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -58,6 +58,7 @@
import com.android.server.FgThread;
import java.util.ArrayList;
+import java.util.function.Consumer;
import java.util.function.LongConsumer;
/**
@@ -476,6 +477,19 @@
return false;
}
+ boolean canApplyDim(@Nullable Task task) {
+ if (task == null) {
+ // Always allow non-activity window.
+ return true;
+ }
+ for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
+ if (!mPlayingTransitions.get(i).canApplyDim(task)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* During transient-launch, the "behind" app should retain focus during the transition unless
* something takes focus from it explicitly (eg. by calling ATMS.setFocusedTask or by another
@@ -1314,18 +1328,18 @@
return transit;
}
- /** Returns {@code true} if it started collecting, {@code false} if it was queued. */
- boolean startLegacySyncOrQueue(BLASTSyncEngine.SyncGroup syncGroup, Runnable applySync) {
+ /** Starts the sync set if there is no pending or active syncs, otherwise enqueue the sync. */
+ void startLegacySyncOrQueue(BLASTSyncEngine.SyncGroup syncGroup, Consumer<Boolean> applySync) {
if (!mQueuedTransitions.isEmpty() || mSyncEngine.hasActiveSync()) {
// Just add to queue since we already have a queue.
- mQueuedTransitions.add(new QueuedTransition(syncGroup, (d) -> applySync.run()));
+ mQueuedTransitions.add(new QueuedTransition(syncGroup,
+ (deferred) -> applySync.accept(true /* deferred */)));
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN,
"Queueing legacy sync-set: %s", syncGroup.mSyncId);
- return false;
+ return;
}
mSyncEngine.startSyncSet(syncGroup);
- applySync.run();
- return true;
+ applySync.accept(false /* deferred */);
}
interface OnStartCollect {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 7f41ff1..eb7b8c2 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -21,7 +21,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
@@ -137,7 +136,8 @@
};
private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> {
- if (!w.mTransitionController.isShellTransitionsEnabled()) {
+ final boolean useShellTransition = w.mTransitionController.isShellTransitionsEnabled();
+ if (!useShellTransition) {
if (w.mActivityRecord != null && !w.mActivityRecord.isVisible()
&& !w.mActivityRecord.isAnimating(TRANSITION | PARENTS)) {
// If this window's app token is hidden and not animating, it is of no interest.
@@ -159,30 +159,23 @@
final WindowContainer animatingContainer = w.mActivityRecord != null
? w.mActivityRecord.getAnimatingContainer() : null;
- final boolean keyguardGoingAwayWithWallpaper = (animatingContainer != null
+ if (!useShellTransition && animatingContainer != null
&& animatingContainer.isAnimating(TRANSITION | PARENTS)
&& AppTransition.isKeyguardGoingAwayTransitOld(animatingContainer.mTransit)
&& (animatingContainer.mTransitFlags
- & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0);
-
- boolean needsShowWhenLockedWallpaper = false;
- if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && mService.mPolicy.isKeyguardLocked()) {
- final TransitionController tc = w.mTransitionController;
- final boolean isInTransition = tc.isShellTransitionsEnabled()
- && tc.inTransition(w);
- if (mService.mPolicy.isKeyguardOccluded() || mService.mPolicy.isKeyguardUnoccluding()
- || isInTransition) {
- // The lowest show when locked window decides whether we need to put the wallpaper
- // behind.
- needsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
- || (w.mActivityRecord != null && !w.mActivityRecord.fillsParent());
- }
+ & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0) {
+ // Keep the wallpaper visible when Keyguard is going away.
+ mFindResults.setUseTopWallpaperAsTarget(true);
}
- if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) {
- // Keep the wallpaper during Keyguard exit but also when it's needed for a
- // non-fullscreen show when locked activity.
- mFindResults.setUseTopWallpaperAsTarget(true);
+ if (mService.mPolicy.isKeyguardLocked() && w.canShowWhenLocked()) {
+ if (mService.mPolicy.isKeyguardOccluded() || (useShellTransition
+ ? w.inTransition() : mService.mPolicy.isKeyguardUnoccluding())) {
+ // The lowest show when locked window decides whether we need to put the wallpaper
+ // behind.
+ mFindResults.mNeedsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
+ || (w.mActivityRecord != null && !w.mActivityRecord.fillsParent());
+ }
}
final boolean animationWallpaper = animatingContainer != null
@@ -691,7 +684,8 @@
private void findWallpaperTarget() {
mFindResults.reset();
- if (mDisplayContent.getDefaultTaskDisplayArea()
+ if (mService.mAtmService.mSupportsFreeformWindowManagement
+ && mDisplayContent.getDefaultTaskDisplayArea()
.isRootTaskVisible(WINDOWING_MODE_FREEFORM)) {
// In freeform mode we set the wallpaper as its own target, so we don't need an
// additional window to make it visible.
@@ -700,6 +694,10 @@
mDisplayContent.forAllWindows(mFindWallpapers, true /* traverseTopToBottom */);
mDisplayContent.forAllWindows(mFindWallpaperTargetFunction, true /* traverseTopToBottom */);
+ if (mFindResults.mNeedsShowWhenLockedWallpaper) {
+ // Keep wallpaper visible if the show-when-locked activities doesn't fill screen.
+ mFindResults.setUseTopWallpaperAsTarget(true);
+ }
if (mFindResults.wallpaperTarget == null && mFindResults.useTopWallpaperAsTarget) {
mFindResults.setWallpaperTarget(
@@ -1084,6 +1082,7 @@
}
TopWallpaper mTopWallpaper = new TopWallpaper();
+ boolean mNeedsShowWhenLockedWallpaper;
boolean useTopWallpaperAsTarget = false;
WindowState wallpaperTarget = null;
boolean isWallpaperTargetForLetterbox = false;
@@ -1132,6 +1131,7 @@
void reset() {
mTopWallpaper.reset();
+ mNeedsShowWhenLockedWallpaper = false;
wallpaperTarget = null;
useTopWallpaperAsTarget = false;
isWallpaperTargetForLetterbox = false;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 8e85e5b..a2f7ba4 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -232,8 +232,8 @@
final BLASTSyncEngine.SyncGroup syncGroup = prepareSyncWithOrganizer(callback);
final int syncId = syncGroup.mSyncId;
if (mTransitionController.isShellTransitionsEnabled()) {
- mTransitionController.startLegacySyncOrQueue(syncGroup, () -> {
- applyTransaction(t, syncId, null /*transition*/, caller);
+ mTransitionController.startLegacySyncOrQueue(syncGroup, (deferred) -> {
+ applyTransaction(t, syncId, null /* transition */, caller, deferred);
setSyncReady(syncId);
});
} else {
@@ -304,7 +304,8 @@
(deferred) -> {
nextTransition.start();
nextTransition.mLogger.mStartWCT = wct;
- applyTransaction(wct, -1 /*syncId*/, nextTransition, caller);
+ applyTransaction(wct, -1 /* syncId */, nextTransition, caller,
+ deferred);
if (needsSetReady) {
nextTransition.setAllReady();
}
@@ -456,7 +457,7 @@
transition.abort();
return;
}
- if (applyTransaction(wct, -1 /* syncId */, transition, caller)
+ if (applyTransaction(wct, -1 /* syncId */, transition, caller, deferred)
== TRANSACT_EFFECTS_NONE && transition.mParticipants.isEmpty()) {
transition.abort();
return;
@@ -476,6 +477,23 @@
return applyTransaction(t, syncId, transition, caller, null /* finishTransition */);
}
+ private int applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
+ @Nullable Transition transition, @NonNull CallerInfo caller, boolean deferred) {
+ if (deferred) {
+ try {
+ return applyTransaction(t, syncId, transition, caller);
+ } catch (RuntimeException e) {
+ // If the transaction is deferred, the caller could be from TransitionController
+ // #tryStartCollectFromQueue that executes on system's worker thread rather than
+ // binder thread. And the operation in the WCT may be outdated that violates the
+ // current state. So catch the exception to avoid crashing the system.
+ Slog.e(TAG, "Failed to execute deferred applyTransaction", e);
+ }
+ return TRANSACT_EFFECTS_NONE;
+ }
+ return applyTransaction(t, syncId, transition, caller);
+ }
+
/**
* @param syncId If non-null, this will be a sync-transaction.
* @param transition A transition to collect changes into.
@@ -838,13 +856,21 @@
switch (type) {
case HIERARCHY_OP_TYPE_REMOVE_TASK: {
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
- final Task task = wc != null ? wc.asTask() : null;
+ if (wc == null || wc.asTask() == null || !wc.isAttached()) {
+ Slog.e(TAG, "Attempt to remove invalid task: " + wc);
+ break;
+ }
+ final Task task = wc.asTask();
task.remove(true, "Applying remove task Hierarchy Op");
break;
}
case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
- final Task task = wc != null ? wc.asTask() : null;
+ if (wc == null || !wc.isAttached()) {
+ Slog.e(TAG, "Attempt to set launch root to a detached container: " + wc);
+ break;
+ }
+ final Task task = wc.asTask();
if (task == null) {
throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc);
} else if (task.getTaskDisplayArea() == null) {
@@ -858,7 +884,11 @@
}
case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: {
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
- final Task task = wc != null ? wc.asTask() : null;
+ if (wc == null || !wc.isAttached()) {
+ Slog.e(TAG, "Attempt to set launch adjacent to a detached container: " + wc);
+ break;
+ }
+ final Task task = wc.asTask();
final boolean clearRoot = hop.getToTop();
if (task == null) {
throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b899b4f..cc9ac76 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2983,10 +2983,11 @@
@Override
public boolean canShowWhenLocked() {
- final boolean showBecauseOfActivity =
- mActivityRecord != null && mActivityRecord.canShowWhenLocked();
- final boolean showBecauseOfWindow = (getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0;
- return showBecauseOfActivity || showBecauseOfWindow;
+ if (mActivityRecord != null) {
+ // It will also check if its windows contain FLAG_SHOW_WHEN_LOCKED.
+ return mActivityRecord.canShowWhenLocked();
+ }
+ return (mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
}
/**
@@ -5119,12 +5120,13 @@
private void applyDims() {
if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || shouldDrawBlurBehind())
- && isVisibleNow() && !mHidden) {
+ && isVisibleNow() && !mHidden && mTransitionController.canApplyDim(getTask())) {
// Only show the Dimmer when the following is satisfied:
// 1. The window has the flag FLAG_DIM_BEHIND or blur behind is requested
// 2. The WindowToken is not hidden so dims aren't shown when the window is exiting.
// 3. The WS is considered visible according to the isVisible() method
// 4. The WS is not hidden.
+ // 5. The window is not in a transition or is in a transition that allows to dim.
mIsDimming = true;
final float dimAmount = (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? mAttrs.dimAmount : 0;
final int blurRadius = shouldDrawBlurBehind() ? mAttrs.getBlurBehindRadius() : 0;
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index cadee6f..a1199d9 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -21,6 +21,7 @@
import static android.content.Context.CREDENTIAL_SERVICE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -55,6 +56,7 @@
import android.provider.Settings;
import android.service.credentials.CallingAppInfo;
import android.service.credentials.CredentialProviderInfoFactory;
+import android.service.credentials.PermissionUtils;
import android.text.TextUtils;
import android.util.Pair;
import android.util.Slog;
@@ -546,11 +548,16 @@
if (providerSessions.isEmpty()) {
try {
- // TODO: fix
prepareGetCredentialCallback.onResponse(
- new PrepareGetCredentialResponseInternal(
- false, null,
- false, false, null));
+ new PrepareGetCredentialResponseInternal(PermissionUtils.hasPermission(
+ mContext,
+ callingPackage,
+ Manifest.permission
+ .CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS),
+ /*credentialResultTypes=*/null,
+ /*hasAuthenticationResults=*/false,
+ /*hasRemoteResults=*/false,
+ /*pendingIntent=*/null));
} catch (RemoteException e) {
Slog.e(
TAG,
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index e7a94c0..7a88069 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -172,6 +172,7 @@
BroadcastConstants mConstants;
private BroadcastSkipPolicy mSkipPolicy;
private UidObserver mUidObserver;
+ private UidObserver mUidCachedStateObserver;
/**
* Desired behavior of the next
@@ -317,7 +318,13 @@
doAnswer((invocation) -> {
mUidObserver = invocation.getArgument(0);
return null;
- }).when(mAms).registerUidObserver(any(), anyInt(), anyInt(), any());
+ }).when(mAms).registerUidObserver(any(), anyInt(),
+ eq(ActivityManager.PROCESS_STATE_TOP), any());
+ doAnswer((invocation) -> {
+ mUidCachedStateObserver = invocation.getArgument(0);
+ return null;
+ }).when(mAms).registerUidObserver(any(), anyInt(),
+ eq(ActivityManager.PROCESS_STATE_LAST_ACTIVITY), any());
mConstants = new BroadcastConstants(Settings.Global.BROADCAST_FG_CONSTANTS);
mConstants.TIMEOUT = 100;
@@ -1762,8 +1769,12 @@
final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
final ProcessRecord receiverOrangeApp = makeActiveProcessRecord(PACKAGE_ORANGE);
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), true);
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), true);
+ mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_GREEN),
+ ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, 0,
+ ActivityManager.PROCESS_CAPABILITY_NONE);
+ mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_BLUE),
+ ActivityManager.PROCESS_STATE_CACHED_EMPTY, 0,
+ ActivityManager.PROCESS_CAPABILITY_NONE);
final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
final BroadcastOptions opts = BroadcastOptions.makeBasic()
@@ -1807,12 +1818,16 @@
eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any());
// Shift blue to be active and confirm that deferred broadcast is delivered
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), false);
+ mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_BLUE),
+ ActivityManager.PROCESS_STATE_TOP, 0,
+ ActivityManager.PROCESS_CAPABILITY_NONE);
waitForIdle();
verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, timeTick);
// Shift green to be active and confirm that deferred broadcast is delivered
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), false);
+ mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_GREEN),
+ ActivityManager.PROCESS_STATE_SERVICE, 0,
+ ActivityManager.PROCESS_CAPABILITY_NONE);
waitForIdle();
verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, timeTick);
}
@@ -2237,9 +2252,15 @@
final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), true);
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), true);
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_YELLOW), false);
+ mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_GREEN),
+ ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, 0,
+ ActivityManager.PROCESS_CAPABILITY_NONE);
+ mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_BLUE),
+ ActivityManager.PROCESS_STATE_CACHED_EMPTY, 0,
+ ActivityManager.PROCESS_CAPABILITY_NONE);
+ mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_YELLOW),
+ ActivityManager.PROCESS_STATE_SERVICE, 0,
+ ActivityManager.PROCESS_CAPABILITY_NONE);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final BroadcastOptions opts = BroadcastOptions.makeBasic()
@@ -2262,7 +2283,9 @@
verifyScheduleRegisteredReceiver(times(1), receiverYellowApp, airplane);
// Shift green to be active and confirm that deferred broadcast is delivered
- mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), false);
+ mUidCachedStateObserver.onUidStateChanged(getUidForPackage(PACKAGE_GREEN),
+ ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0,
+ ActivityManager.PROCESS_CAPABILITY_NONE);
waitForIdle();
verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, airplane);
}
diff --git a/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java b/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java
index 851d8f9..f05fa65 100644
--- a/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/dreams/DreamOverlayServiceTest.java
@@ -101,12 +101,6 @@
mMonitor.onEndDream();
super.onEndDream();
}
-
- @Override
- public void onWakeUp(@NonNull Runnable onCompleteCallback) {
- mMonitor.onWakeUp();
- super.onWakeUp(onCompleteCallback);
- }
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index aad373f..aca96ad 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -445,14 +445,14 @@
+ " <library \n"
+ " name=\"foo\"\n"
+ " file=\"" + mFooJar + "\"\n"
- + " on-bootclasspath-before=\"A\"\n"
+ + " on-bootclasspath-before=\"Q\"\n"
+ " on-bootclasspath-since=\"W\"\n"
+ " />\n\n"
+ " </permissions>";
parseSharedLibraries(contents);
assertFooIsOnlySharedLibrary();
SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo");
- assertThat(entry.onBootclasspathBefore).isEqualTo("A");
+ assertThat(entry.onBootclasspathBefore).isEqualTo("Q");
assertThat(entry.onBootclasspathSince).isEqualTo("W");
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 1126726..ed0c8ef 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -1452,6 +1452,11 @@
}
});
assertTrue(activity1.isVisible());
+ doReturn(false).when(task1).isTranslucent(null);
+ assertTrue(controller.canApplyDim(task1));
+ doReturn(true).when(task1).isTranslucent(null);
+ assertFalse(controller.canApplyDim(task1));
+
controller.finishTransition(closeTransition);
assertTrue(wasInFinishingTransition[0]);
assertNull(controller.mFinishingTransition);
@@ -2191,8 +2196,11 @@
BLASTSyncEngine.SyncGroup legacySync = mSyncEngine.prepareSyncSet(
mock(BLASTSyncEngine.TransactionReadyListener.class), "test");
- final boolean[] applyLegacy = new boolean[]{false};
- controller.startLegacySyncOrQueue(legacySync, () -> applyLegacy[0] = true);
+ final boolean[] applyLegacy = new boolean[2];
+ controller.startLegacySyncOrQueue(legacySync, (deferred) -> {
+ applyLegacy[0] = true;
+ applyLegacy[1] = deferred;
+ });
assertFalse(applyLegacy[0]);
waitUntilHandlersIdle();
@@ -2208,6 +2216,7 @@
assertTrue(transitA.isPlaying());
// legacy sync should start now
assertTrue(applyLegacy[0]);
+ assertTrue(applyLegacy[1]);
// transitB must wait
assertTrue(transitB.isPending());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index f3d8114..4afcd05 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -288,6 +288,32 @@
assertEquals(homeWin, dc.mWallpaperController.getWallpaperTarget());
}
+ @Test
+ public void testShowWhenLockedWallpaperTarget() {
+ final WindowState wallpaperWindow = createWallpaperWindow(mDisplayContent);
+ wallpaperWindow.mToken.asWallpaperToken().setShowWhenLocked(true);
+ final WindowState behind = createWindow(null, TYPE_BASE_APPLICATION, "behind");
+ final WindowState topTranslucent = createWindow(null, TYPE_BASE_APPLICATION,
+ "topTranslucent");
+ behind.mAttrs.width = behind.mAttrs.height = topTranslucent.mAttrs.width =
+ topTranslucent.mAttrs.height = WindowManager.LayoutParams.MATCH_PARENT;
+ topTranslucent.mAttrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+ doReturn(true).when(behind.mActivityRecord).fillsParent();
+ doReturn(false).when(topTranslucent.mActivityRecord).fillsParent();
+
+ spyOn(mWm.mPolicy);
+ doReturn(true).when(mWm.mPolicy).isKeyguardLocked();
+ doReturn(true).when(mWm.mPolicy).isKeyguardOccluded();
+ mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+ // Wallpaper is visible because the show-when-locked activity is translucent.
+ assertTrue(mDisplayContent.mWallpaperController.isWallpaperTarget(wallpaperWindow));
+
+ behind.mActivityRecord.setShowWhenLocked(true);
+ mDisplayContent.mWallpaperController.adjustWallpaperWindows();
+ // Wallpaper is invisible because the lowest show-when-locked activity is opaque.
+ assertTrue(mDisplayContent.mWallpaperController.isWallpaperTarget(null));
+ }
+
/**
* Tests that the windowing mode of the wallpaper window must always be fullscreen.
*/