summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2020-09-25 05:28:24 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2020-09-25 05:28:24 +0000
commit33d7e9308e8b1bfa692ca62d7d198d62e238e8b7 (patch)
tree236d08a091e0b330ad1c167ab98820553423a24d
parent1ff495f0f4fbd6c988867f9b69a923a417a7ffea (diff)
parentd6af5b5d1e5986c2d63dfc89d996c899416cf9f8 (diff)
Merge "Make process level rotated config and display metrics consistent" into rvc-qpr-dev am: d6af5b5d1e
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12670488 Change-Id: I1ca8add8df59a72e35ced7d0f888c662e01d7dc2
-rw-r--r--core/java/android/app/ActivityThread.java99
-rw-r--r--core/java/android/app/ResourcesManager.java15
-rw-r--r--core/java/android/view/DisplayAdjustments.java40
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java5
-rw-r--r--core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java18
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java15
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java80
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java52
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java9
10 files changed, 231 insertions, 114 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a01b7cba967d..3466a7817d6f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3250,12 +3250,6 @@ public final class ActivityThread extends ClientTransactionHandler {
sendMessage(H.CLEAN_UP_CONTEXT, cci);
}
- @Override
- public void handleFixedRotationAdjustments(@NonNull IBinder token,
- @Nullable FixedRotationAdjustments fixedRotationAdjustments) {
- handleFixedRotationAdjustments(token, fixedRotationAdjustments, null /* overrideConfig */);
- }
-
/**
* Applies the rotation adjustments to override display information in resources belong to the
* provided token. If the token is activity token, the adjustments also apply to application
@@ -3265,51 +3259,39 @@ public final class ActivityThread extends ClientTransactionHandler {
* @param fixedRotationAdjustments The information to override the display adjustments of
* corresponding resources. If it is null, the exiting override
* will be cleared.
- * @param overrideConfig The override configuration of activity. It is used to override
- * application configuration. If it is non-null, it means the token is
- * confirmed as activity token. Especially when launching new activity,
- * {@link #mActivities} hasn't put the new token.
*/
- private void handleFixedRotationAdjustments(@NonNull IBinder token,
- @Nullable FixedRotationAdjustments fixedRotationAdjustments,
- @Nullable Configuration overrideConfig) {
- // The element of application configuration override is set only if the application
- // adjustments are needed, because activity already has its own override configuration.
- final Configuration[] appConfigOverride;
- final Consumer<DisplayAdjustments> override;
- if (fixedRotationAdjustments != null) {
- appConfigOverride = new Configuration[1];
- override = displayAdjustments -> {
- displayAdjustments.setFixedRotationAdjustments(fixedRotationAdjustments);
- if (appConfigOverride[0] != null) {
- displayAdjustments.getConfiguration().updateFrom(appConfigOverride[0]);
- }
- };
- } else {
- appConfigOverride = null;
- override = null;
- }
+ @Override
+ public void handleFixedRotationAdjustments(@NonNull IBinder token,
+ @Nullable FixedRotationAdjustments fixedRotationAdjustments) {
+ final Consumer<DisplayAdjustments> override = fixedRotationAdjustments != null
+ ? displayAdjustments -> displayAdjustments
+ .setFixedRotationAdjustments(fixedRotationAdjustments)
+ : null;
if (!mResourcesManager.overrideTokenDisplayAdjustments(token, override)) {
// No resources are associated with the token.
return;
}
- if (overrideConfig == null) {
- final ActivityClientRecord r = mActivities.get(token);
- if (r == null) {
- // It is not an activity token. Nothing to do for application.
- return;
- }
- overrideConfig = r.overrideConfig;
- }
- if (appConfigOverride != null) {
- appConfigOverride[0] = overrideConfig;
+ if (mActivities.get(token) == null) {
+ // Nothing to do for application if it is not an activity token.
+ return;
}
- // Apply the last override to application resources for compatibility. Because the Resources
- // of Display can be from application, e.g.
- // applicationContext.getSystemService(DisplayManager.class).getDisplay(displayId)
- // and the deprecated usage:
- // applicationContext.getSystemService(WindowManager.class).getDefaultDisplay();
+ overrideApplicationDisplayAdjustments(token, override);
+ }
+
+ /**
+ * Applies the last override to application resources for compatibility. Because the Resources
+ * of Display can be from application, e.g.
+ * applicationContext.getSystemService(DisplayManager.class).getDisplay(displayId)
+ * and the deprecated usage:
+ * applicationContext.getSystemService(WindowManager.class).getDefaultDisplay();
+ *
+ * @param token The owner and target of the override.
+ * @param override The display adjustments override for application resources. If it is null,
+ * the override of the token will be removed and pop the last one to use.
+ */
+ private void overrideApplicationDisplayAdjustments(@NonNull IBinder token,
+ @Nullable Consumer<DisplayAdjustments> override) {
final Consumer<DisplayAdjustments> appOverride;
if (mActiveRotationAdjustments == null) {
mActiveRotationAdjustments = new ArrayList<>(2);
@@ -3542,8 +3524,13 @@ public final class ActivityThread extends ClientTransactionHandler {
// The rotation adjustments must be applied before creating the activity, so the activity
// can get the adjusted display info during creation.
if (r.mPendingFixedRotationAdjustments != null) {
- handleFixedRotationAdjustments(r.token, r.mPendingFixedRotationAdjustments,
- r.overrideConfig);
+ // The adjustments should have been set by handleLaunchActivity, so the last one is the
+ // override for activity resources.
+ if (mActiveRotationAdjustments != null && !mActiveRotationAdjustments.isEmpty()) {
+ mResourcesManager.overrideTokenDisplayAdjustments(r.token,
+ mActiveRotationAdjustments.get(
+ mActiveRotationAdjustments.size() - 1).second);
+ }
r.mPendingFixedRotationAdjustments = null;
}
@@ -3582,6 +3569,13 @@ public final class ActivityThread extends ClientTransactionHandler {
mProfiler.startProfiling();
}
+ if (r.mPendingFixedRotationAdjustments != null) {
+ // The rotation adjustments must be applied before handling configuration, so process
+ // level display metrics can be adjusted.
+ overrideApplicationDisplayAdjustments(r.token, adjustments ->
+ adjustments.setFixedRotationAdjustments(r.mPendingFixedRotationAdjustments));
+ }
+
// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);
@@ -5777,7 +5771,15 @@ public final class ActivityThread extends ClientTransactionHandler {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: "
+ config);
- mResourcesManager.applyConfigurationToResourcesLocked(config, compat);
+ final Resources appResources = mInitialApplication.getResources();
+ if (appResources.hasOverrideDisplayAdjustments()) {
+ // The value of Display#getRealSize will be adjusted by FixedRotationAdjustments,
+ // but Display#getSize refers to DisplayAdjustments#mConfiguration. So the rotated
+ // configuration also needs to set to the adjustments for consistency.
+ appResources.getDisplayAdjustments().getConfiguration().updateFrom(config);
+ }
+ mResourcesManager.applyConfigurationToResourcesLocked(config, compat,
+ appResources.getDisplayAdjustments());
updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
mResourcesManager.getConfiguration().getLocales());
@@ -7390,7 +7392,8 @@ public final class ActivityThread extends ClientTransactionHandler {
// We need to apply this change to the resources immediately, because upon returning
// the view hierarchy will be informed about it.
if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
- null /* compat */)) {
+ null /* compat */,
+ mInitialApplication.getResources().getDisplayAdjustments())) {
updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
mResourcesManager.getConfiguration().getLocales());
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 0b278a9f972a..771528ad39c3 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -1069,12 +1069,18 @@ public class ResourcesManager {
public final boolean applyConfigurationToResources(@NonNull Configuration config,
@Nullable CompatibilityInfo compat) {
synchronized(this) {
- return applyConfigurationToResourcesLocked(config, compat);
+ return applyConfigurationToResourcesLocked(config, compat, null /* adjustments */);
}
}
public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config,
- @Nullable CompatibilityInfo compat) {
+ @Nullable CompatibilityInfo compat) {
+ return applyConfigurationToResourcesLocked(config, compat, null /* adjustments */);
+ }
+
+ /** Applies the global configuration to the managed resources. */
+ public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config,
+ @Nullable CompatibilityInfo compat, @Nullable DisplayAdjustments adjustments) {
try {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
"ResourcesManager#applyConfigurationToResourcesLocked");
@@ -1098,6 +1104,11 @@ public class ResourcesManager {
| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
}
+ if (adjustments != null) {
+ // Currently the only case where the adjustment takes effect is to simulate placing
+ // an app in a rotated display.
+ adjustments.adjustGlobalAppMetrics(defaultDisplayMetrics);
+ }
Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat);
ApplicationPackageManager.configurationChanged();
diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java
index c726bee9f402..7c01f7a8739a 100644
--- a/core/java/android/view/DisplayAdjustments.java
+++ b/core/java/android/view/DisplayAdjustments.java
@@ -130,14 +130,16 @@ public class DisplayAdjustments {
w = metrics.noncompatWidthPixels;
metrics.noncompatWidthPixels = metrics.noncompatHeightPixels;
metrics.noncompatHeightPixels = w;
+ }
- float x = metrics.xdpi;
- metrics.xdpi = metrics.ydpi;
- metrics.ydpi = x;
-
- x = metrics.noncompatXdpi;
- metrics.noncompatXdpi = metrics.noncompatYdpi;
- metrics.noncompatYdpi = x;
+ /** Adjusts global display metrics that is available to applications. */
+ public void adjustGlobalAppMetrics(@NonNull DisplayMetrics metrics) {
+ final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments;
+ if (rotationAdjustments == null) {
+ return;
+ }
+ metrics.noncompatWidthPixels = metrics.widthPixels = rotationAdjustments.mAppWidth;
+ metrics.noncompatHeightPixels = metrics.heightPixels = rotationAdjustments.mAppHeight;
}
/** Returns the adjusted cutout if available. Otherwise the original cutout is returned. */
@@ -178,7 +180,7 @@ public class DisplayAdjustments {
/**
* An application can be launched in different rotation than the real display. This class
- * provides the information to adjust the values returned by {@link #Display}.
+ * provides the information to adjust the values returned by {@link Display}.
* @hide
*/
public static class FixedRotationAdjustments implements Parcelable {
@@ -186,12 +188,24 @@ public class DisplayAdjustments {
@Surface.Rotation
final int mRotation;
+ /**
+ * The rotated {@link DisplayInfo#appWidth}. The value cannot be simply swapped according
+ * to rotation because it minus the region of screen decorations.
+ */
+ final int mAppWidth;
+
+ /** The rotated {@link DisplayInfo#appHeight}. */
+ final int mAppHeight;
+
/** Non-null if the device has cutout. */
@Nullable
final DisplayCutout mRotatedDisplayCutout;
- public FixedRotationAdjustments(@Surface.Rotation int rotation, DisplayCutout cutout) {
+ public FixedRotationAdjustments(@Surface.Rotation int rotation, int appWidth, int appHeight,
+ DisplayCutout cutout) {
mRotation = rotation;
+ mAppWidth = appWidth;
+ mAppHeight = appHeight;
mRotatedDisplayCutout = cutout;
}
@@ -199,6 +213,8 @@ public class DisplayAdjustments {
public int hashCode() {
int hash = 17;
hash = hash * 31 + mRotation;
+ hash = hash * 31 + mAppWidth;
+ hash = hash * 31 + mAppHeight;
hash = hash * 31 + Objects.hashCode(mRotatedDisplayCutout);
return hash;
}
@@ -210,12 +226,14 @@ public class DisplayAdjustments {
}
final FixedRotationAdjustments other = (FixedRotationAdjustments) o;
return mRotation == other.mRotation
+ && mAppWidth == other.mAppWidth && mAppHeight == other.mAppHeight
&& Objects.equals(mRotatedDisplayCutout, other.mRotatedDisplayCutout);
}
@Override
public String toString() {
return "FixedRotationAdjustments{rotation=" + Surface.rotationToString(mRotation)
+ + " appWidth=" + mAppWidth + " appHeight=" + mAppHeight
+ " cutout=" + mRotatedDisplayCutout + "}";
}
@@ -227,12 +245,16 @@ public class DisplayAdjustments {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mRotation);
+ dest.writeInt(mAppWidth);
+ dest.writeInt(mAppHeight);
dest.writeTypedObject(
new DisplayCutout.ParcelableWrapper(mRotatedDisplayCutout), flags);
}
private FixedRotationAdjustments(Parcel in) {
mRotation = in.readInt();
+ mAppWidth = in.readInt();
+ mAppHeight = in.readInt();
final DisplayCutout.ParcelableWrapper cutoutWrapper =
in.readTypedObject(DisplayCutout.ParcelableWrapper.CREATOR);
mRotatedDisplayCutout = cutoutWrapper != null ? cutoutWrapper.get() : null;
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index f11adef81793..7d2e32ab08d3 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -191,7 +191,7 @@ public class TransactionParcelTests {
PersistableBundle persistableBundle = new PersistableBundle();
persistableBundle.putInt("k", 4);
FixedRotationAdjustments fixedRotationAdjustments = new FixedRotationAdjustments(
- Surface.ROTATION_90, DisplayCutout.NO_CUTOUT);
+ Surface.ROTATION_90, 1920, 1080, DisplayCutout.NO_CUTOUT);
LaunchActivityItem item = LaunchActivityItem.obtain(intent, ident, activityInfo,
config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
@@ -351,7 +351,8 @@ public class TransactionParcelTests {
ClientTransaction transaction = ClientTransaction.obtain(new StubAppThread(),
null /* activityToken */);
transaction.addCallback(FixedRotationAdjustmentsItem.obtain(new Binder(),
- new FixedRotationAdjustments(Surface.ROTATION_270, DisplayCutout.NO_CUTOUT)));
+ new FixedRotationAdjustments(Surface.ROTATION_270, 1920, 1080,
+ DisplayCutout.NO_CUTOUT)));
writeAndPrepareForReading(transaction);
diff --git a/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java b/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java
index 2fc42e91a8cc..3cf1722d49d3 100644
--- a/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java
+++ b/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java
@@ -77,8 +77,10 @@ public class DisplayAdjustmentsTests {
final int realRotation = Surface.ROTATION_0;
final int fixedRotation = Surface.ROTATION_90;
- mDisplayAdjustments.setFixedRotationAdjustments(
- new FixedRotationAdjustments(fixedRotation, null /* cutout */));
+ final int appWidth = 1080;
+ final int appHeight = 1920;
+ mDisplayAdjustments.setFixedRotationAdjustments(new FixedRotationAdjustments(
+ fixedRotation, appWidth, appHeight, null /* cutout */));
final int w = 1000;
final int h = 2000;
@@ -95,13 +97,21 @@ public class DisplayAdjustmentsTests {
metrics.heightPixels = metrics.noncompatHeightPixels = h;
final DisplayMetrics flippedMetrics = new DisplayMetrics();
- flippedMetrics.xdpi = flippedMetrics.noncompatXdpi = h;
+ // The physical dpi should not be adjusted.
+ flippedMetrics.xdpi = flippedMetrics.noncompatXdpi = w;
flippedMetrics.widthPixels = flippedMetrics.noncompatWidthPixels = h;
- flippedMetrics.ydpi = flippedMetrics.noncompatYdpi = w;
+ flippedMetrics.ydpi = flippedMetrics.noncompatYdpi = h;
flippedMetrics.heightPixels = flippedMetrics.noncompatHeightPixels = w;
mDisplayAdjustments.adjustMetrics(metrics, realRotation);
assertEquals(flippedMetrics, metrics);
+
+ mDisplayAdjustments.adjustGlobalAppMetrics(metrics);
+
+ assertEquals(appWidth, metrics.widthPixels);
+ assertEquals(appWidth, metrics.noncompatWidthPixels);
+ assertEquals(appHeight, metrics.heightPixels);
+ assertEquals(appHeight, metrics.noncompatHeightPixels);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 3dd82a6221c6..7e6b7cd05762 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -732,6 +732,11 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
final ActivityStack stack = task.getStack();
beginDeferResume();
+ // The LaunchActivityItem also contains process configuration, so the configuration change
+ // from WindowProcessController#setProcess can be deferred. The major reason is that if
+ // the activity has FixedRotationAdjustments, it needs to be applied with configuration.
+ // In general, this reduces a binder transaction if process configuration is changed.
+ proc.pauseConfigurationDispatch();
try {
r.startFreezingScreenLocked(proc, 0);
@@ -826,9 +831,9 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// Because we could be starting an Activity in the system process this may not go
// across a Binder interface which would create a new Configuration. Consequently
// we have to always create a new Configuration here.
-
+ final Configuration procConfig = proc.prepareConfigurationForLaunchingActivity();
final MergedConfiguration mergedConfiguration = new MergedConfiguration(
- proc.getConfiguration(), r.getMergedOverrideConfiguration());
+ procConfig, r.getMergedOverrideConfiguration());
r.setLastReportedConfiguration(mergedConfiguration);
logIfTransactionTooLarge(r.intent, r.getSavedState());
@@ -862,6 +867,11 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
+ if (procConfig.seq > mRootWindowContainer.getConfiguration().seq) {
+ // If the seq is increased, there should be something changed (e.g. registered
+ // activity configuration).
+ proc.setLastReportedConfiguration(procConfig);
+ }
if ((proc.mInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0
&& mService.mHasHeavyWeightFeature) {
// This may be a heavy-weight process! Note that the package manager will ensure
@@ -896,6 +906,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
} finally {
endDeferResume();
+ proc.resumeConfigurationDispatch();
}
r.launchFailed = false;
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index bd959aba5bb1..df49ac71334f 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -186,13 +186,16 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
// Last configuration that was reported to the process.
private final Configuration mLastReportedConfiguration = new Configuration();
- // Configuration that is waiting to be dispatched to the process.
- private Configuration mPendingConfiguration;
+ /** Whether the process configuration is waiting to be dispatched to the process. */
+ private boolean mHasPendingConfigurationChange;
// Registered display id as a listener to override config change
private int mDisplayId;
private ActivityRecord mConfigActivityRecord;
// Whether the activity config override is allowed for this process.
private volatile boolean mIsActivityConfigOverrideAllowed = true;
+ /** Non-zero to pause dispatching process configuration change. */
+ private int mPauseConfigurationDispatchCount;
+
/**
* Activities that hosts some UI drawn by the current process. The activities live
* in another process. This is used to check if the process is currently showing anything
@@ -1115,8 +1118,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
onMergedOverrideConfigurationChanged(Configuration.EMPTY);
}
- private void registerActivityConfigurationListener(ActivityRecord activityRecord) {
- if (activityRecord == null || activityRecord.containsListener(this)) {
+ void registerActivityConfigurationListener(ActivityRecord activityRecord) {
+ if (activityRecord == null || activityRecord.containsListener(this)
+ // Check for the caller from outside of this class.
+ || !mIsActivityConfigOverrideAllowed) {
return;
}
// A process can only register to one activityRecord to listen to the override configuration
@@ -1168,25 +1173,25 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
@Override
public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
- super.onRequestedOverrideConfigurationChanged(
- sanitizeProcessConfiguration(overrideConfiguration));
+ super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
}
@Override
public void onMergedOverrideConfigurationChanged(Configuration mergedOverrideConfig) {
- super.onRequestedOverrideConfigurationChanged(
- sanitizeProcessConfiguration(mergedOverrideConfig));
+ super.onRequestedOverrideConfigurationChanged(mergedOverrideConfig);
}
- private static Configuration sanitizeProcessConfiguration(Configuration config) {
+ @Override
+ void resolveOverrideConfiguration(Configuration newParentConfig) {
+ super.resolveOverrideConfiguration(newParentConfig);
+ final Configuration resolvedConfig = getResolvedOverrideConfiguration();
// Make sure that we don't accidentally override the activity type.
- if (config.windowConfiguration.getActivityType() != ACTIVITY_TYPE_UNDEFINED) {
- final Configuration sanitizedConfig = new Configuration(config);
- sanitizedConfig.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED);
- return sanitizedConfig;
- }
-
- return config;
+ resolvedConfig.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED);
+ // Activity has an independent ActivityRecord#mConfigurationSeq. If this process registers
+ // activity configuration, its config seq shouldn't go backwards by activity configuration.
+ // Otherwise if other places send wpc.getConfiguration() to client, the configuration may
+ // be ignored due to the seq is older.
+ resolvedConfig.seq = newParentConfig.seq;
}
private void updateConfiguration() {
@@ -1204,11 +1209,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
if (mListener.isCached()) {
// This process is in a cached state. We will delay delivering the config change to the
// process until the process is no longer cached.
- if (mPendingConfiguration == null) {
- mPendingConfiguration = new Configuration(config);
- } else {
- mPendingConfiguration.setTo(config);
- }
+ mHasPendingConfigurationChange = true;
return;
}
@@ -1216,6 +1217,11 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
private void dispatchConfigurationChange(Configuration config) {
+ if (mPauseConfigurationDispatchCount > 0) {
+ mHasPendingConfigurationChange = true;
+ return;
+ }
+ mHasPendingConfigurationChange = false;
if (mThread == null) {
if (Build.IS_DEBUGGABLE && mHasImeService) {
// TODO (b/135719017): Temporary log for debugging IME service.
@@ -1242,7 +1248,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
}
- private void setLastReportedConfiguration(Configuration config) {
+ void setLastReportedConfiguration(Configuration config) {
mLastReportedConfiguration.setTo(config);
}
@@ -1250,6 +1256,30 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return mLastReportedConfiguration;
}
+ void pauseConfigurationDispatch() {
+ mPauseConfigurationDispatchCount++;
+ }
+
+ void resumeConfigurationDispatch() {
+ mPauseConfigurationDispatchCount--;
+ }
+
+ /**
+ * This is called for sending {@link android.app.servertransaction.LaunchActivityItem}.
+ * The caller must call {@link #setLastReportedConfiguration} if the delivered configuration
+ * is newer.
+ */
+ Configuration prepareConfigurationForLaunchingActivity() {
+ final Configuration config = getConfiguration();
+ if (mHasPendingConfigurationChange) {
+ mHasPendingConfigurationChange = false;
+ // The global configuration may not change, so the client process may have the same
+ // config seq. This increment ensures that the client won't ignore the configuration.
+ config.seq = mAtm.increaseConfigurationSeqLocked();
+ }
+ return config;
+ }
+
/** Returns the total time (in milliseconds) spent executing in both user and system code. */
public long getCpuTime() {
return (mListener != null) ? mListener.getCpuTime() : 0;
@@ -1341,10 +1371,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
public void onProcCachedStateChanged(boolean isCached) {
if (!isCached) {
synchronized (mAtm.mGlobalLockWithoutBoost) {
- if (mPendingConfiguration != null) {
- final Configuration config = mPendingConfiguration;
- mPendingConfiguration = null;
- dispatchConfigurationChange(config);
+ if (mHasPendingConfigurationChange) {
+ dispatchConfigurationChange(getConfiguration());
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 1716dcd5ee16..d86f6c998baa 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -172,6 +172,12 @@ class WindowToken extends WindowContainer<WindowState> {
}
}
}
+
+ /** The state may not only be used by self. Make sure to leave the influence by others. */
+ void disassociate(WindowToken token) {
+ mAssociatedTokens.remove(token);
+ mRotatedContainers.remove(token);
+ }
}
private class DeathRecipient implements IBinder.DeathRecipient {
@@ -531,7 +537,7 @@ class WindowToken extends WindowContainer<WindowState> {
void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames,
Configuration config) {
if (mFixedRotationTransformState != null) {
- cleanUpFixedRotationTransformState(true /* replacing */);
+ mFixedRotationTransformState.disassociate(this);
}
mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames,
new Configuration(config), mDisplayContent.getRotation());
@@ -539,8 +545,7 @@ class WindowToken extends WindowContainer<WindowState> {
mDisplayContent.getDisplayPolicy().simulateLayoutDisplay(displayFrames,
mFixedRotationTransformState.mInsetsState,
mFixedRotationTransformState.mBarContentFrames);
- onConfigurationChanged(getParent().getConfiguration());
- notifyFixedRotationTransform(true /* enabled */);
+ onFixedRotationStatePrepared();
}
/**
@@ -553,12 +558,29 @@ class WindowToken extends WindowContainer<WindowState> {
return;
}
if (mFixedRotationTransformState != null) {
- cleanUpFixedRotationTransformState(true /* replacing */);
+ mFixedRotationTransformState.disassociate(this);
}
mFixedRotationTransformState = fixedRotationState;
fixedRotationState.mAssociatedTokens.add(this);
- onConfigurationChanged(getParent().getConfiguration());
+ onFixedRotationStatePrepared();
+ }
+
+ /**
+ * Makes the rotated states take effect for this window container and its client process.
+ * This should only be called when {@link #mFixedRotationTransformState} is non-null.
+ */
+ private void onFixedRotationStatePrepared() {
+ // Send the adjustment info first so when the client receives configuration change, it can
+ // get the rotated display metrics.
notifyFixedRotationTransform(true /* enabled */);
+ // Resolve the rotated configuration.
+ onConfigurationChanged(getParent().getConfiguration());
+ final ActivityRecord r = asActivityRecord();
+ if (r != null && r.hasProcess()) {
+ // The application needs to be configured as in a rotated environment for compatibility.
+ // This registration will send the rotated configuration to its process.
+ r.app.registerActivityConfigurationListener(r);
+ }
}
/**
@@ -609,21 +631,12 @@ class WindowToken extends WindowContainer<WindowState> {
// The state is cleared at the end, because it is used to indicate that other windows can
// use seamless rotation when applying rotation to display.
for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) {
- state.mAssociatedTokens.get(i).cleanUpFixedRotationTransformState(
- false /* replacing */);
+ final WindowToken token = state.mAssociatedTokens.get(i);
+ token.mFixedRotationTransformState = null;
+ token.notifyFixedRotationTransform(false /* enabled */);
}
}
- private void cleanUpFixedRotationTransformState(boolean replacing) {
- if (replacing && mFixedRotationTransformState.mAssociatedTokens.size() > 1) {
- // The state is not only used by self. Make sure to leave the influence by others.
- mFixedRotationTransformState.mAssociatedTokens.remove(this);
- mFixedRotationTransformState.mRotatedContainers.remove(this);
- }
- mFixedRotationTransformState = null;
- notifyFixedRotationTransform(false /* enabled */);
- }
-
/** Notifies application side to enable or disable the rotation adjustment of display info. */
private void notifyFixedRotationTransform(boolean enabled) {
FixedRotationAdjustments adjustments = null;
@@ -687,8 +700,9 @@ class WindowToken extends WindowContainer<WindowState> {
if (!isFixedRotationTransforming()) {
return null;
}
- return new FixedRotationAdjustments(mFixedRotationTransformState.mDisplayInfo.rotation,
- mFixedRotationTransformState.mDisplayInfo.displayCutout);
+ final DisplayInfo displayInfo = mFixedRotationTransformState.mDisplayInfo;
+ return new FixedRotationAdjustments(displayInfo.rotation, displayInfo.appWidth,
+ displayInfo.appHeight, displayInfo.displayCutout);
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 6a84c1390150..c7a8bd857674 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1149,8 +1149,10 @@ public class DisplayContentTests extends WindowTestsBase {
verify(t, never()).setPosition(any(), eq(0), eq(0));
// Launch another activity before the transition is finished.
- final ActivityRecord app2 = new ActivityTestsBase.StackBuilder(mWm.mRoot)
- .setDisplay(mDisplayContent).build().getTopMostActivity();
+ final ActivityStack stack2 = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ .setDisplay(mDisplayContent).build();
+ final ActivityRecord app2 = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ .setStack(stack2).setUseProcess(app.app).build();
app2.setVisible(false);
mDisplayContent.mOpeningApps.add(app2);
app2.setRequestedOrientation(newOrientation);
@@ -1160,6 +1162,12 @@ public class DisplayContentTests extends WindowTestsBase {
assertTrue(app.hasFixedRotationTransform(app2));
assertTrue(mDisplayContent.isFixedRotationLaunchingApp(app2));
+ final Configuration expectedProcConfig = new Configuration(app2.app.getConfiguration());
+ expectedProcConfig.windowConfiguration.setActivityType(
+ WindowConfiguration.ACTIVITY_TYPE_UNDEFINED);
+ assertEquals("The process should receive rotated configuration for compatibility",
+ expectedProcConfig, app2.app.getConfiguration());
+
// The fixed rotation transform can only be finished when all animation finished.
doReturn(false).when(app2).isAnimating(anyInt(), anyInt());
mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app2.token);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 24950ce6a882..a46e6d35ee97 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -266,6 +266,15 @@ public class WindowProcessControllerTests extends ActivityTestsBase {
mWpc.onMergedOverrideConfigurationChanged(config);
assertEquals(ACTIVITY_TYPE_HOME, config.windowConfiguration.getActivityType());
assertEquals(ACTIVITY_TYPE_UNDEFINED, mWpc.getActivityType());
+
+ final int globalSeq = 100;
+ mRootWindowContainer.getConfiguration().seq = globalSeq;
+ invertOrientation(mWpc.getConfiguration());
+ new ActivityBuilder(mService).setCreateTask(true).setUseProcess(mWpc).build();
+
+ assertTrue(mWpc.registeredForActivityConfigChanges());
+ assertEquals("Config seq of process should not be affected by activity",
+ mWpc.getConfiguration().seq, globalSeq);
}
private TestDisplayContent createTestDisplayContentInContainer() {