Merge "Make process level rotated config and display metrics consistent" into rvc-qpr-dev

This commit is contained in:
TreeHugger Robot
2020-09-25 03:54:37 +00:00
committed by Android (Google) Code Review
10 changed files with 231 additions and 114 deletions

View File

@@ -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());

View File

@@ -1071,12 +1071,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");
@@ -1100,6 +1106,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();

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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());
}
}
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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() {