diff options
| author | 2020-09-25 05:28:24 +0000 | |
|---|---|---|
| committer | 2020-09-25 05:28:24 +0000 | |
| commit | 33d7e9308e8b1bfa692ca62d7d198d62e238e8b7 (patch) | |
| tree | 236d08a091e0b330ad1c167ab98820553423a24d | |
| parent | 1ff495f0f4fbd6c988867f9b69a923a417a7ffea (diff) | |
| parent | d6af5b5d1e5986c2d63dfc89d996c899416cf9f8 (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
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() { |