Merge "Make process level rotated config and display metrics consistent" into rvc-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d6af5b5d1e
@@ -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());
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user