summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt10
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt6
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java50
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java15
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java40
-rw-r--r--services/core/java/com/android/server/wm/LetterboxUiController.java119
-rw-r--r--services/core/java/com/android/server/wm/TransparentPolicy.java107
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java40
9 files changed, 168 insertions, 226 deletions
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index c477f30a1d2f..08846f0fed96 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -45,8 +45,8 @@ import androidx.credentials.CreateCredentialRequest
import androidx.credentials.CreateCustomCredentialRequest
import androidx.credentials.CreatePasswordRequest
import androidx.credentials.CreatePublicKeyCredentialRequest
+import androidx.credentials.CredentialOption
import androidx.credentials.PasswordCredential
-import androidx.credentials.PriorityHints
import androidx.credentials.PublicKeyCredential
import androidx.credentials.provider.CreateEntry
import androidx.credentials.provider.RemoteEntry
@@ -177,9 +177,9 @@ class GetFlowUtils {
"androidx.credentials.BUNDLE_KEY_TYPE_PRIORITY_VALUE",
when (option.type) {
PasswordCredential.TYPE_PASSWORD_CREDENTIAL ->
- PriorityHints.PRIORITY_PASSWORD_OR_SIMILAR
+ CredentialOption.PRIORITY_PASSWORD_OR_SIMILAR
PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL -> 100
- else -> PriorityHints.PRIORITY_DEFAULT
+ else -> CredentialOption.PRIORITY_DEFAULT
}
)
typePriorityMap[option.type] = priority
@@ -349,8 +349,8 @@ class CreateFlowUtils {
}
is CreateCustomCredentialRequest -> {
// TODO: directly use the display info once made public
- val displayInfo = CreateCredentialRequest.DisplayInfo
- .parseFromCredentialDataBundle(createCredentialRequest.credentialData)
+ val displayInfo = CreateCredentialRequest.DisplayInfo.createFrom(
+ createCredentialRequest.credentialData)
?: return null
RequestDisplayInfo(
title = displayInfo.userId.toString(),
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
index 19f5a99f46fa..314cc0547b89 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
@@ -19,7 +19,7 @@ package com.android.credentialmanager.getflow
import android.credentials.flags.Flags.selectorUiImprovementsEnabled
import android.credentials.flags.Flags.credmanBiometricApiEnabled
import android.graphics.drawable.Drawable
-import androidx.credentials.PriorityHints
+import androidx.credentials.CredentialOption
import com.android.credentialmanager.R
import com.android.credentialmanager.model.CredentialType
import com.android.credentialmanager.model.get.ProviderInfo
@@ -322,10 +322,10 @@ internal class CredentialEntryInfoComparatorByTypeThenTimestamp(
// First rank by priorities of each credential type.
if (p0.rawCredentialType != p1.rawCredentialType) {
val p0Priority = typePriorityMap.getOrDefault(
- p0.rawCredentialType, PriorityHints.PRIORITY_DEFAULT
+ p0.rawCredentialType, CredentialOption.PRIORITY_DEFAULT
)
val p1Priority = typePriorityMap.getOrDefault(
- p1.rawCredentialType, PriorityHints.PRIORITY_DEFAULT
+ p1.rawCredentialType, CredentialOption.PRIORITY_DEFAULT
)
if (p0Priority < p1Priority) {
return -1
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 69f07d5c5f7b..fc75bf47ed96 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -81,6 +81,8 @@ import android.util.Log;
import android.util.Slog;
import android.view.KeyEvent;
+import com.android.internal.annotations.GuardedBy;
+import com.android.media.flags.Flags;
import com.android.server.LocalServices;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -229,6 +231,14 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde
private int mPolicies;
+ private final Runnable mUserEngagementTimeoutExpirationRunnable =
+ () -> {
+ synchronized (mLock) {
+ updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true);
+ }
+ };
+
+ @GuardedBy("mLock")
private @UserEngagementState int mUserEngagementState = USER_DISENGAGED;
@IntDef({USER_PERMANENTLY_ENGAGED, USER_TEMPORARY_ENGAGED, USER_DISENGAGED})
@@ -238,26 +248,26 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde
/**
* Indicates that the session is active and in one of the user engaged states.
*
- * @see #updateUserEngagedStateIfNeededLocked(boolean) ()
+ * @see #updateUserEngagedStateIfNeededLocked(boolean)
*/
private static final int USER_PERMANENTLY_ENGAGED = 0;
/**
* Indicates that the session is active and in {@link PlaybackState#STATE_PAUSED} state.
*
- * @see #updateUserEngagedStateIfNeededLocked(boolean) ()
+ * @see #updateUserEngagedStateIfNeededLocked(boolean)
*/
private static final int USER_TEMPORARY_ENGAGED = 1;
/**
* Indicates that the session is either not active or in one of the user disengaged states
*
- * @see #updateUserEngagedStateIfNeededLocked(boolean) ()
+ * @see #updateUserEngagedStateIfNeededLocked(boolean)
*/
private static final int USER_DISENGAGED = 2;
/**
- * Indicates the duration of the temporary engaged states.
+ * Indicates the duration of the temporary engaged states, in milliseconds.
*
* <p>Some {@link MediaSession} states like {@link PlaybackState#STATE_PAUSED} are temporarily
* engaged, meaning the corresponding session is only considered in an engaged state for the
@@ -270,7 +280,7 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde
* user-engaged state is not considered user-engaged when transitioning from a non-user engaged
* state {@link PlaybackState#STATE_STOPPED}.
*/
- private static final int TEMP_USER_ENGAGED_TIMEOUT = 600000;
+ private static final int TEMP_USER_ENGAGED_TIMEOUT_MS = 600000;
public MediaSessionRecord(
int ownerPid,
@@ -609,8 +619,7 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde
@Override
public void expireTempEngaged() {
- mHandler.removeCallbacks(mHandleTempEngagedSessionTimeout);
- updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true);
+ mHandler.post(mUserEngagementTimeoutExpirationRunnable);
}
/**
@@ -1086,11 +1095,6 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde
}
};
- private final Runnable mHandleTempEngagedSessionTimeout =
- () -> {
- updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true);
- };
-
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
private static boolean componentNameExists(
@NonNull ComponentName componentName, @NonNull Context context, int userId) {
@@ -1107,10 +1111,14 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde
return !resolveInfos.isEmpty();
}
+ @GuardedBy("mLock")
private void updateUserEngagedStateIfNeededLocked(boolean isTimeoutExpired) {
+ if (!Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange()) {
+ return;
+ }
int oldUserEngagedState = mUserEngagementState;
int newUserEngagedState;
- if (!isActive() || mPlaybackState == null) {
+ if (!isActive() || mPlaybackState == null || mDestroyed) {
newUserEngagedState = USER_DISENGAGED;
} else if (isActive() && mPlaybackState.isActive()) {
newUserEngagedState = USER_PERMANENTLY_ENGAGED;
@@ -1126,18 +1134,22 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde
return;
}
+ mUserEngagementState = newUserEngagedState;
if (newUserEngagedState == USER_TEMPORARY_ENGAGED) {
- mHandler.postDelayed(mHandleTempEngagedSessionTimeout, TEMP_USER_ENGAGED_TIMEOUT);
- } else if (oldUserEngagedState == USER_TEMPORARY_ENGAGED) {
- mHandler.removeCallbacks(mHandleTempEngagedSessionTimeout);
+ mHandler.postDelayed(
+ mUserEngagementTimeoutExpirationRunnable, TEMP_USER_ENGAGED_TIMEOUT_MS);
+ } else {
+ mHandler.removeCallbacks(mUserEngagementTimeoutExpirationRunnable);
}
boolean wasUserEngaged = oldUserEngagedState != USER_DISENGAGED;
boolean isNowUserEngaged = newUserEngagedState != USER_DISENGAGED;
- mUserEngagementState = newUserEngagedState;
if (wasUserEngaged != isNowUserEngaged) {
- mService.onSessionUserEngagementStateChange(
- /* mediaSessionRecord= */ this, /* isUserEngaged= */ isNowUserEngaged);
+ mHandler.post(
+ () ->
+ mService.onSessionUserEngagementStateChange(
+ /* mediaSessionRecord= */ this,
+ /* isUserEngaged= */ isNowUserEngaged));
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 399866728770..f02a3fff12f5 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -715,6 +715,12 @@ public class MediaSessionService extends SystemService implements Monitor {
ForegroundServiceDelegationOptions foregroundServiceDelegationOptions) {
final long token = Binder.clearCallingIdentity();
try {
+ Log.i(
+ TAG,
+ TextUtils.formatSimple(
+ "startFgsDelegate: pkg=%s uid=%d",
+ foregroundServiceDelegationOptions.mClientPackageName,
+ foregroundServiceDelegationOptions.mClientUid));
mActivityManagerInternal.startForegroundServiceDelegate(
foregroundServiceDelegationOptions, /* connection= */ null);
} finally {
@@ -756,6 +762,12 @@ public class MediaSessionService extends SystemService implements Monitor {
ForegroundServiceDelegationOptions foregroundServiceDelegationOptions) {
final long token = Binder.clearCallingIdentity();
try {
+ Log.i(
+ TAG,
+ TextUtils.formatSimple(
+ "stopFgsDelegate: pkg=%s uid=%d",
+ foregroundServiceDelegationOptions.mClientPackageName,
+ foregroundServiceDelegationOptions.mClientUid));
mActivityManagerInternal.stopForegroundServiceDelegate(
foregroundServiceDelegationOptions);
} finally {
@@ -2679,6 +2691,9 @@ public class MediaSessionService extends SystemService implements Monitor {
@Override
public void expireTempEngagedSessions() {
+ if (!Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange()) {
+ return;
+ }
synchronized (mLock) {
for (Set<MediaSessionRecordImpl> uidSessions :
mUserEngagedSessionsForFgs.values()) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 2d2a88a866ba..fec1af47d6e6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -803,6 +803,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final LetterboxUiController mLetterboxUiController;
/**
+ * The policy for transparent activities
+ */
+ final TransparentPolicy mTransparentPolicy;
+
+ /**
* The scale to fit at least one side of the activity to its parent. If the activity uses
* 1920x1080, and the actually size on the screen is 960x540, then the scale is 0.5.
*/
@@ -1698,7 +1703,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (isState(RESUMED)) {
newParent.setResumedActivity(this, "onParentChanged");
}
- mLetterboxUiController.updateInheritedLetterbox();
+ mTransparentPolicy.start();
}
if (rootTask != null && rootTask.topRunningActivity() == this) {
@@ -2136,6 +2141,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Don't move below setOrientation(info.screenOrientation) since it triggers
// getOverrideOrientation that requires having mLetterboxUiController
// initialised.
+ mTransparentPolicy = new TransparentPolicy(this, mWmService.mLetterboxConfiguration);
mLetterboxUiController = new LetterboxUiController(mWmService, this);
mCameraCompatControlEnabled = mWmService.mContext.getResources()
.getBoolean(R.bool.config_isCameraCompatControlForStretchedIssuesEnabled);
@@ -8080,13 +8086,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Configuration.Orientation
int getRequestedConfigurationOrientation(boolean forDisplay,
@ActivityInfo.ScreenOrientation int requestedOrientation) {
- if (mLetterboxUiController.hasInheritedOrientation()) {
+ if (mTransparentPolicy.hasInheritedOrientation()) {
final RootDisplayArea root = getRootDisplayArea();
if (forDisplay && root != null && root.isOrientationDifferentFromDisplay()) {
return reverseConfigurationOrientation(
- mLetterboxUiController.getInheritedOrientation());
+ mTransparentPolicy.getInheritedOrientation());
} else {
- return mLetterboxUiController.getInheritedOrientation();
+ return mTransparentPolicy.getInheritedOrientation();
}
}
if (task != null && requestedOrientation == SCREEN_ORIENTATION_BEHIND) {
@@ -8302,8 +8308,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Nullable
CompatDisplayInsets getCompatDisplayInsets() {
- if (mLetterboxUiController.hasInheritedLetterboxBehavior()) {
- return mLetterboxUiController.getInheritedCompatDisplayInsets();
+ if (mTransparentPolicy.isRunning()) {
+ return mTransparentPolicy.getInheritedCompatDisplayInsets();
}
return mCompatDisplayInsets;
}
@@ -8466,7 +8472,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
mSizeCompatBounds = null;
mCompatDisplayInsets = null;
- mLetterboxUiController.clearInheritedCompatDisplayInsets();
+ mTransparentPolicy.clearInheritedCompatDisplayInsets();
}
@VisibleForTesting
@@ -8784,8 +8790,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
}
// TODO(b/256564921): Investigate if we need new metrics for translucent activities
- if (mLetterboxUiController.hasInheritedLetterboxBehavior()) {
- return mLetterboxUiController.getInheritedAppCompatState();
+ if (mTransparentPolicy.isRunning()) {
+ return mTransparentPolicy.getInheritedAppCompatState();
}
if (mInSizeCompatModeForBounds) {
return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
@@ -8938,7 +8944,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// We check if the current activity is transparent. In that case we need to
// recomputeConfiguration of the first opaque activity beneath, to allow a
// proper computation of the new bounds.
- if (!mLetterboxUiController.applyOnOpaqueActivityBelow(
+ if (!mTransparentPolicy.applyOnOpaqueActivityBelow(
ActivityRecord::recomputeConfiguration)) {
onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
}
@@ -9411,7 +9417,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
void updateSizeCompatScale(Rect resolvedAppBounds, Rect containerAppBounds) {
// Only allow to scale down.
- mSizeCompatScale = mLetterboxUiController.findOpaqueNotFinishingActivityBelow()
+ mSizeCompatScale = mTransparentPolicy.findOpaqueNotFinishingActivityBelow()
.map(activityRecord -> activityRecord.mSizeCompatScale)
.orElseGet(() -> {
final int contentW = resolvedAppBounds.width();
@@ -9424,7 +9430,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
private boolean isInSizeCompatModeForBounds(final Rect appBounds, final Rect containerBounds) {
- if (mLetterboxUiController.hasInheritedLetterboxBehavior()) {
+ if (mTransparentPolicy.isRunning()) {
// To avoid wrong app behaviour, we decided to disable SCM when a translucent activity
// is letterboxed.
return false;
@@ -9487,7 +9493,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
public Rect getBounds() {
// TODO(b/268458693): Refactor configuration inheritance in case of translucent activities
final Rect superBounds = super.getBounds();
- return mLetterboxUiController.findOpaqueNotFinishingActivityBelow()
+ return mTransparentPolicy.findOpaqueNotFinishingActivityBelow()
.map(ActivityRecord::getBounds)
.orElseGet(() -> {
if (mSizeCompatBounds != null) {
@@ -9851,8 +9857,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* Returns the min aspect ratio of this activity.
*/
float getMinAspectRatio() {
- if (mLetterboxUiController.hasInheritedLetterboxBehavior()) {
- return mLetterboxUiController.getInheritedMinAspectRatio();
+ if (mTransparentPolicy.isRunning()) {
+ return mTransparentPolicy.getInheritedMinAspectRatio();
}
if (info.applicationInfo == null) {
return info.getMinAspectRatio();
@@ -9902,8 +9908,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
float getMaxAspectRatio() {
- if (mLetterboxUiController.hasInheritedLetterboxBehavior()) {
- return mLetterboxUiController.getInheritedMaxAspectRatio();
+ if (mTransparentPolicy.isRunning()) {
+ return mTransparentPolicy.getInheritedMaxAspectRatio();
}
return info.getMaxAspectRatio();
}
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index ce71f81bff94..194771f6b387 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -129,10 +129,7 @@ import com.android.server.wm.utils.OptPropFactory.OptProp;
import com.android.window.flags.Flags;
import java.io.PrintWriter;
-import java.util.Optional;
import java.util.function.BooleanSupplier;
-import java.util.function.Consumer;
-import java.util.function.Predicate;
/** Controls behaviour of the letterbox UI for {@link mActivityRecord}. */
// TODO(b/185262487): Improve test coverage of this class. Parts of it are tested in
@@ -228,10 +225,6 @@ final class LetterboxUiController {
@NonNull
private final OptProp mFakeFocusOptProp;
- // TODO(b/336807329) Eventually eemove this dependency when refactoring Reachability.
- @NonNull
- private final TransparentPolicy mTransparentPolicy;
-
private boolean mIsRelaunchingAfterRequestedOrientationChanged;
private boolean mLastShouldShowLetterboxUi;
@@ -245,24 +238,6 @@ final class LetterboxUiController {
// to use it after since controller is only used in ActivityRecord.
mActivityRecord = activityRecord;
- mTransparentPolicy = new TransparentPolicy(activityRecord, mLetterboxConfiguration,
- new Predicate<ActivityRecord>() {
- @Override
- public boolean test(ActivityRecord opaqueActivity) {
- if (opaqueActivity == null || opaqueActivity.isEmbedded()) {
- // We skip letterboxing if the translucent activity doesn't have any
- // opaque activities beneath or the activity below is embedded which
- // never has letterbox.
- mActivityRecord.recomputeConfiguration();
- return true;
- }
- if (mActivityRecord.getTask() == null || mActivityRecord.fillsParent()
- || mActivityRecord.hasCompatDisplayInsetsWithoutInheritance()) {
- return true;
- }
- return false;
- }
- });
PackageManager packageManager = wmService.mContext.getPackageManager();
final OptPropFactory optPropBuilder = new OptPropFactory(packageManager,
@@ -340,7 +315,7 @@ final class LetterboxUiController {
mLetterbox.destroy();
mLetterbox = null;
}
- mTransparentPolicy.stop();
+ mActivityRecord.mTransparentPolicy.stop();
}
void onMovedToDisplay(int displayId) {
@@ -349,11 +324,6 @@ final class LetterboxUiController {
}
}
- @NonNull
- TransparentPolicy getTransparentPolicy() {
- return mTransparentPolicy;
- }
-
/**
* Whether should ignore app requested orientation in response to an app
* calling {@link android.app.Activity#setRequestedOrientation}.
@@ -854,7 +824,7 @@ final class LetterboxUiController {
// For this reason we use ActivityRecord#getBounds() that the translucent activity
// inherits from the first opaque activity beneath and also takes care of the scaling
// in case of activities in size compat mode.
- final Rect innerFrame = hasInheritedLetterboxBehavior()
+ final Rect innerFrame = mActivityRecord.mTransparentPolicy.isRunning()
? mActivityRecord.getBounds() : w.getFrame();
mLetterbox.layout(spaceToFill, innerFrame, mTmpPoint);
if (mDoubleTapEvent) {
@@ -1320,10 +1290,9 @@ final class LetterboxUiController {
}
// Use screen resolved bounds which uses resolved bounds or size compat bounds
// as activity bounds can sometimes be empty
- final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior()
- ? getTransparentPolicy().getTransparentPolicyState()
- .mFirstOpaqueActivity.getScreenResolvedBounds()
- : mActivityRecord.getScreenResolvedBounds();
+ final Rect opaqueActivityBounds = mActivityRecord.mTransparentPolicy
+ .getFirstOpaqueActivity().map(ActivityRecord::getScreenResolvedBounds)
+ .orElse(mActivityRecord.getScreenResolvedBounds());
return mLetterboxConfiguration.getIsHorizontalReachabilityEnabled()
&& parentConfiguration.windowConfiguration.getWindowingMode()
== WINDOWING_MODE_FULLSCREEN
@@ -1358,11 +1327,10 @@ final class LetterboxUiController {
return false;
}
// Use screen resolved bounds which uses resolved bounds or size compat bounds
- // as activity bounds can sometimes be empty
- final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior()
- ? getTransparentPolicy().getTransparentPolicyState()
- .mFirstOpaqueActivity.getScreenResolvedBounds()
- : mActivityRecord.getScreenResolvedBounds();
+ // as activity bounds can sometimes be empty.
+ final Rect opaqueActivityBounds = mActivityRecord.mTransparentPolicy
+ .getFirstOpaqueActivity().map(ActivityRecord::getScreenResolvedBounds)
+ .orElse(mActivityRecord.getScreenResolvedBounds());
return mLetterboxConfiguration.getIsVerticalReachabilityEnabled()
&& parentConfiguration.windowConfiguration.getWindowingMode()
== WINDOWING_MODE_FULLSCREEN
@@ -1469,7 +1437,8 @@ final class LetterboxUiController {
// corners because we assume the specific layout would. This is the case when the layout
// of the translucent activity uses only a part of all the bounds because of the use of
// LayoutParams.WRAP_CONTENT.
- if (hasInheritedLetterboxBehavior() && (cropBounds.width() != mainWindow.mRequestedWidth
+ if (mActivityRecord.mTransparentPolicy.isRunning()
+ && (cropBounds.width() != mainWindow.mRequestedWidth
|| cropBounds.height() != mainWindow.mRequestedHeight)) {
return null;
}
@@ -1773,72 +1742,6 @@ final class LetterboxUiController {
);
}
- /**
- * Handles translucent activities letterboxing inheriting constraints from the
- * first opaque activity beneath.
- */
- void updateInheritedLetterbox() {
- mTransparentPolicy.start();
- }
-
- /**
- * @return {@code true} if the current activity is translucent with an opaque activity
- * beneath. In this case it will inherit bounds, orientation and aspect ratios from
- * the first opaque activity beneath.
- */
- boolean hasInheritedLetterboxBehavior() {
- return mTransparentPolicy.hasInheritedLetterboxBehavior();
- }
-
- /**
- * @return {@code true} if the current activity is translucent with an opaque activity
- * beneath and needs to inherit its orientation.
- */
- boolean hasInheritedOrientation() {
- return mTransparentPolicy.hasInheritedOrientation();
- }
-
- float getInheritedMinAspectRatio() {
- return mTransparentPolicy.getInheritedMinAspectRatio();
- }
-
- float getInheritedMaxAspectRatio() {
- return mTransparentPolicy.getInheritedMaxAspectRatio();
- }
-
- int getInheritedAppCompatState() {
- return mTransparentPolicy.getInheritedAppCompatState();
- }
-
- @Configuration.Orientation
- int getInheritedOrientation() {
- return mTransparentPolicy.getInheritedOrientation();
- }
-
- ActivityRecord.CompatDisplayInsets getInheritedCompatDisplayInsets() {
- return mTransparentPolicy.getInheritedCompatDisplayInsets();
- }
-
- void clearInheritedCompatDisplayInsets() {
- mTransparentPolicy.clearInheritedCompatDisplayInsets();
- }
-
- /**
- * In case of translucent activities, it consumes the {@link ActivityRecord} of the first opaque
- * activity beneath using the given consumer and returns {@code true}.
- */
- boolean applyOnOpaqueActivityBelow(@NonNull Consumer<ActivityRecord> consumer) {
- return mTransparentPolicy.applyOnOpaqueActivityBelow(consumer);
- }
-
- /**
- * @return The first not finishing opaque activity beneath the current translucent activity
- * if it exists and the strategy is enabled.
- */
- Optional<ActivityRecord> findOpaqueNotFinishingActivityBelow() {
- return mTransparentPolicy.findOpaqueNotFinishingActivityBelow();
- }
-
@NonNull
private static BooleanSupplier asLazy(@NonNull BooleanSupplier supplier) {
return new BooleanSupplier() {
diff --git a/services/core/java/com/android/server/wm/TransparentPolicy.java b/services/core/java/com/android/server/wm/TransparentPolicy.java
index f8a6fe1c825c..b408397d1861 100644
--- a/services/core/java/com/android/server/wm/TransparentPolicy.java
+++ b/services/core/java/com/android/server/wm/TransparentPolicy.java
@@ -40,6 +40,11 @@ import java.util.function.Predicate;
/**
* Encapsulate logic about translucent activities.
+ * <p/>
+ * An activity is defined as translucent if {@link ActivityRecord#fillsParent()} returns
+ * {@code false}. When the policy is running for a letterboxed activity, a transparent activity
+ * will inherit constraints about bounds, aspect ratios and orientation from the first not finishing
+ * activity below.
*/
class TransparentPolicy {
@@ -50,30 +55,28 @@ class TransparentPolicy {
private static final Predicate<ActivityRecord> FIRST_OPAQUE_NOT_FINISHING_ACTIVITY_PREDICATE =
ActivityRecord::occludesParent;
- // The predicate to check to skip the policy
- @NonNull
- private final Predicate<ActivityRecord> mSkipLetterboxPredicate;
-
// The ActivityRecord this policy relates to.
+ @NonNull
private final ActivityRecord mActivityRecord;
// If transparent activity policy is enabled.
+ @NonNull
private final BooleanSupplier mIsTranslucentLetterboxingEnabledSupplier;
// The list of observers for the destroy event of candidate opaque activities
// when dealing with translucent activities.
+ @NonNull
private final List<TransparentPolicy> mDestroyListeners = new ArrayList<>();
- // THe current state for the possible transparent activity
+ // The current state for the possible transparent activity
+ @NonNull
private final TransparentPolicyState mTransparentPolicyState;
TransparentPolicy(@NonNull ActivityRecord activityRecord,
- @NonNull LetterboxConfiguration letterboxConfiguration,
- @NonNull Predicate<ActivityRecord> skipLetterboxPredicate) {
+ @NonNull LetterboxConfiguration letterboxConfiguration) {
mActivityRecord = activityRecord;
- mIsTranslucentLetterboxingEnabledSupplier = () -> letterboxConfiguration
- .isTranslucentLetterboxingEnabled();
- mSkipLetterboxPredicate = skipLetterboxPredicate;
+ mIsTranslucentLetterboxingEnabledSupplier =
+ letterboxConfiguration::isTranslucentLetterboxingEnabled;
mTransparentPolicyState = new TransparentPolicyState(activityRecord);
}
@@ -98,7 +101,7 @@ class TransparentPolicy {
true /* traverseTopToBottom */);
// We check if we need for some reason to skip the policy gievn the specific first
// opaque activity
- if (mSkipLetterboxPredicate.test(firstOpaqueActivity)) {
+ if (shouldSkipTransparentPolicy(firstOpaqueActivity)) {
return;
}
mTransparentPolicyState.start(firstOpaqueActivity);
@@ -112,7 +115,12 @@ class TransparentPolicy {
mTransparentPolicyState.reset();
}
- boolean hasInheritedLetterboxBehavior() {
+ /**
+ * @return {@code true} if the current activity is translucent with an opaque activity
+ * beneath and the related policy is running. In this case it will inherit bounds, orientation
+ * and aspect ratios from the first opaque activity beneath.
+ */
+ boolean isRunning() {
return mTransparentPolicyState.isRunning();
}
@@ -121,35 +129,33 @@ class TransparentPolicy {
* beneath and needs to inherit its orientation.
*/
boolean hasInheritedOrientation() {
- // To force a different orientation, the transparent one needs to have an explicit one
- // otherwise the existing one is fine and the actual orientation will depend on the
- // bounds.
- // To avoid wrong behaviour, we're not forcing orientation for activities with not
- // fixed orientation (e.g. permission dialogs).
- return hasInheritedLetterboxBehavior()
+ // To avoid wrong behaviour (e.g. permission dialogs not centered or with wrong size),
+ // transparent activities inherit orientation from the first opaque activity below only if
+ // they explicitly define an orientation different from SCREEN_ORIENTATION_UNSPECIFIED.
+ return isRunning()
&& mActivityRecord.getOverrideOrientation()
!= SCREEN_ORIENTATION_UNSPECIFIED;
}
float getInheritedMinAspectRatio() {
- return mTransparentPolicyState.getInheritedMinAspectRatio();
+ return mTransparentPolicyState.mInheritedMinAspectRatio;
}
float getInheritedMaxAspectRatio() {
- return mTransparentPolicyState.getInheritedMaxAspectRatio();
+ return mTransparentPolicyState.mInheritedMaxAspectRatio;
}
int getInheritedAppCompatState() {
- return mTransparentPolicyState.getInheritedAppCompatState();
+ return mTransparentPolicyState.mInheritedAppCompatState;
}
@Configuration.Orientation
int getInheritedOrientation() {
- return mTransparentPolicyState.getInheritedOrientation();
+ return mTransparentPolicyState.mInheritedOrientation;
}
ActivityRecord.CompatDisplayInsets getInheritedCompatDisplayInsets() {
- return mTransparentPolicyState.getInheritedCompatDisplayInsets();
+ return mTransparentPolicyState.mInheritedCompatDisplayInsets;
}
void clearInheritedCompatDisplayInsets() {
@@ -168,6 +174,12 @@ class TransparentPolicy {
return mTransparentPolicyState.applyOnOpaqueActivityBelow(consumer);
}
+ @NonNull
+ Optional<ActivityRecord> getFirstOpaqueActivity() {
+ return isRunning() ? Optional.of(mTransparentPolicyState.mFirstOpaqueActivity)
+ : Optional.empty();
+ }
+
/**
* @return The first not finishing opaque activity beneath the current translucent activity
* if it exists and the strategy is enabled.
@@ -176,6 +188,22 @@ class TransparentPolicy {
return mTransparentPolicyState.findOpaqueNotFinishingActivityBelow();
}
+ // We evaluate the case when the policy should not be applied.
+ private boolean shouldSkipTransparentPolicy(@Nullable ActivityRecord opaqueActivity) {
+ if (opaqueActivity == null || opaqueActivity.isEmbedded()) {
+ // We skip letterboxing if the translucent activity doesn't have any
+ // opaque activities beneath or the activity below is embedded which
+ // never has letterbox.
+ mActivityRecord.recomputeConfiguration();
+ return true;
+ }
+ if (mActivityRecord.getTask() == null || mActivityRecord.fillsParent()
+ || mActivityRecord.hasCompatDisplayInsetsWithoutInheritance()) {
+ return true;
+ }
+ return false;
+ }
+
/** Resets the screen size related fields so they can be resolved by requested bounds later. */
private static void resetTranslucentOverrideConfig(Configuration config) {
// The values for the following properties will be defined during the configuration
@@ -212,10 +240,11 @@ class TransparentPolicy {
private int mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN;
// The CompatDisplayInsets of the opaque activity beneath the translucent one.
+ @Nullable
private ActivityRecord.CompatDisplayInsets mInheritedCompatDisplayInsets;
@Nullable
- ActivityRecord mFirstOpaqueActivity;
+ private ActivityRecord mFirstOpaqueActivity;
/*
* WindowContainerListener responsible to make translucent activities inherit
@@ -231,9 +260,8 @@ class TransparentPolicy {
private void start(@NonNull ActivityRecord firstOpaqueActivity) {
mFirstOpaqueActivity = firstOpaqueActivity;
- mFirstOpaqueActivity.mLetterboxUiController.getTransparentPolicy()
- .mDestroyListeners.add(mActivityRecord.mLetterboxUiController
- .getTransparentPolicy());
+ mFirstOpaqueActivity.mTransparentPolicy
+ .mDestroyListeners.add(mActivityRecord.mTransparentPolicy);
inheritFromOpaque(firstOpaqueActivity);
final WindowContainer<?> parent = mActivityRecord.getParent();
mLetterboxConfigListener = WindowContainer.overrideConfigurationPropagation(
@@ -284,9 +312,8 @@ class TransparentPolicy {
mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN;
mInheritedCompatDisplayInsets = null;
if (mFirstOpaqueActivity != null) {
- mFirstOpaqueActivity.mLetterboxUiController.getTransparentPolicy()
- .mDestroyListeners.remove(mActivityRecord.mLetterboxUiController
- .getTransparentPolicy());
+ mFirstOpaqueActivity.mTransparentPolicy
+ .mDestroyListeners.remove(mActivityRecord.mTransparentPolicy);
}
mFirstOpaqueActivity = null;
}
@@ -295,26 +322,6 @@ class TransparentPolicy {
return mLetterboxConfigListener != null;
}
- private int getInheritedOrientation() {
- return mInheritedOrientation;
- }
-
- private float getInheritedMinAspectRatio() {
- return mInheritedMinAspectRatio;
- }
-
- private float getInheritedMaxAspectRatio() {
- return mInheritedMaxAspectRatio;
- }
-
- private int getInheritedAppCompatState() {
- return mInheritedAppCompatState;
- }
-
- private ActivityRecord.CompatDisplayInsets getInheritedCompatDisplayInsets() {
- return mInheritedCompatDisplayInsets;
- }
-
private void clearInheritedCompatDisplayInsets() {
mInheritedCompatDisplayInsets = null;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index c7f502045ac8..8129c3d030be 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -77,6 +77,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.annotation.Nullable;
import android.compat.testing.PlatformCompatChangeRule;
@@ -110,7 +111,7 @@ import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
/**
- * Test class for {@link LetterboxUiControllerTest}.
+ * Test class for {@link LetterboxUiController}.
*
* Build/Install/Run:
* atest WmTests:LetterboxUiControllerTest
@@ -521,8 +522,8 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
final Rect opaqueBounds = new Rect(0, 0, 500, 300);
doReturn(opaqueBounds).when(mActivity).getBounds();
// Activity is translucent
- spyOn(mActivity.mLetterboxUiController);
- doReturn(true).when(mActivity.mLetterboxUiController).hasInheritedLetterboxBehavior();
+ spyOn(mActivity.mTransparentPolicy);
+ when(mActivity.mTransparentPolicy.isRunning()).thenReturn(true);
// Makes requested sizes different
mainWindow.mRequestedWidth = opaqueBounds.width() - 1;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index b4ab0caa1071..c81ead9bd0d1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -215,7 +215,7 @@ public class SizeCompatTests extends WindowTestsBase {
translucentActivity.setState(DESTROYED, "testing");
translucentActivity.removeImmediately();
- assertFalse(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());
+ assertFalse(translucentActivity.mTransparentPolicy.isRunning());
}
@Test
@@ -376,7 +376,7 @@ public class SizeCompatTests extends WindowTestsBase {
.build();
mTask.addChild(opaqueActivity);
// Transparent activity strategy not applied
- assertFalse(opaqueActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());
+ assertFalse(opaqueActivity.mTransparentPolicy.isRunning());
// Launch translucent Activity
final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
@@ -386,17 +386,17 @@ public class SizeCompatTests extends WindowTestsBase {
.build();
mTask.addChild(translucentActivity);
// Transparent strategy applied
- assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());
+ assertTrue(translucentActivity.mTransparentPolicy.isRunning());
- spyOn(translucentActivity.mLetterboxUiController.getTransparentPolicy());
- clearInvocations(translucentActivity.mLetterboxUiController.getTransparentPolicy());
+ spyOn(translucentActivity.mTransparentPolicy);
+ clearInvocations(translucentActivity.mTransparentPolicy);
// We destroy the first opaque activity
opaqueActivity.setState(DESTROYED, "testing");
opaqueActivity.removeImmediately();
// Check that updateInheritedLetterbox() is invoked again
- verify(translucentActivity.mLetterboxUiController.getTransparentPolicy()).start();
+ verify(translucentActivity.mTransparentPolicy).start();
}
// TODO(b/333663877): Enable test after fix
@@ -464,18 +464,17 @@ public class SizeCompatTests extends WindowTestsBase {
.build();
mTask.addChild(translucentActivity);
// Transparent strategy applied
- assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());
+ assertTrue(translucentActivity.mTransparentPolicy.isRunning());
- spyOn(translucentActivity.mLetterboxUiController.getTransparentPolicy());
- clearInvocations(translucentActivity.mLetterboxUiController.getTransparentPolicy());
+ spyOn(translucentActivity.mTransparentPolicy);
+ clearInvocations(translucentActivity.mTransparentPolicy);
// We destroy the first opaque activity
mActivity.removeImmediately();
- // Check that start() is invoked again on the TransparentPolicy
- verify(translucentActivity.mLetterboxUiController.getTransparentPolicy()).start();
- assertFalse(translucentActivity.mLetterboxUiController
- .getTransparentPolicy().hasInheritedLetterboxBehavior());
+ // Check that updateInheritedLetterbox() is invoked again on the TransparentPolicy
+ verify(translucentActivity.mTransparentPolicy).start();
+ assertFalse(translucentActivity.mTransparentPolicy.isRunning());
}
@Test
@@ -491,7 +490,7 @@ public class SizeCompatTests extends WindowTestsBase {
.build();
mTask.addChild(opaqueActivity);
// Transparent activity strategy not applied
- assertFalse(opaqueActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());
+ assertFalse(opaqueActivity.mTransparentPolicy.isRunning());
// Launch translucent Activity
final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
@@ -501,14 +500,13 @@ public class SizeCompatTests extends WindowTestsBase {
.build();
mTask.addChild(translucentActivity);
// Transparent strategy applied
- assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());
+ assertTrue(translucentActivity.mTransparentPolicy.isRunning());
- spyOn(translucentActivity.mLetterboxUiController.getTransparentPolicy());
- clearInvocations(translucentActivity.mLetterboxUiController.getTransparentPolicy());
+ spyOn(translucentActivity.mTransparentPolicy);
+ clearInvocations(translucentActivity.mTransparentPolicy);
// Check that updateInheritedLetterbox() is invoked again
- verify(translucentActivity.mLetterboxUiController.getTransparentPolicy(), never())
- .start();
+ verify(translucentActivity.mTransparentPolicy, never()).start();
}
@Test
@@ -616,7 +614,7 @@ public class SizeCompatTests extends WindowTestsBase {
doReturn(false).when(translucentActivity).matchParentBounds();
mTask.addChild(translucentActivity);
// Check the strategy has not being applied
- assertFalse(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());
+ assertFalse(translucentActivity.mTransparentPolicy.isRunning());
}
@Test
@@ -662,7 +660,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertFalse(mActivity.occludesParent());
mTask.addChild(translucentActivity);
// The translucent activity won't inherit letterbox behavior from a finishing activity.
- assertFalse(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());
+ assertFalse(translucentActivity.mTransparentPolicy.isRunning());
}
@Test