Apply override scale from entry points on client
This provides a sandbox-like scaled environment on client side.
- This prevents the metrics and config from being scaled multiple
times because the entry points are only called from server side,
there won't have reentrancy for applying the scale.
- App's configuration callback method can get scaled config.
- If override scale is enabled, the legacy compat mode will be
skipped. That avoids mixing different approaches of scaling.
- Legacy compat mode is to simulate a 320dp x 480dp screen
size with density 160 (the surface scale and config scale
are different).
- Override scale is to downscale the app for better performance
(the surface scale and config scale are the same).
Bug: 238416387
Bug: 240335717
Test: atest ActivityThreadTest#testOverrideScale
Test: atest CtsWindowManagerDeviceTestCases:CompatScaleTests
Test: am compat enable DOWNSCALED $pkg
am compat enable DOWNSCALE_50 $pkg
Change-Id: I0ddf333996f229063511273f8aeb3867c9ba8bda
This commit is contained in:
@@ -1177,9 +1177,16 @@ public final class ActivityThread extends ClientTransactionHandler
|
||||
data.mSerializedSystemFontMap = serializedSystemFontMap;
|
||||
data.startRequestedElapsedTime = startRequestedElapsedTime;
|
||||
data.startRequestedUptime = startRequestedUptime;
|
||||
updateCompatOverrideScale(compatInfo);
|
||||
CompatibilityInfo.applyOverrideScaleIfNeeded(config);
|
||||
sendMessage(H.BIND_APPLICATION, data);
|
||||
}
|
||||
|
||||
private void updateCompatOverrideScale(CompatibilityInfo info) {
|
||||
CompatibilityInfo.setOverrideInvertedScale(
|
||||
info.hasOverrideScaling() ? info.applicationInvertedScale : 1f);
|
||||
}
|
||||
|
||||
public final void runIsolatedEntryPoint(String entryPoint, String[] entryPointArgs) {
|
||||
SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = entryPoint;
|
||||
@@ -1756,6 +1763,7 @@ public final class ActivityThread extends ClientTransactionHandler
|
||||
UpdateCompatibilityData ucd = new UpdateCompatibilityData();
|
||||
ucd.pkg = pkg;
|
||||
ucd.info = info;
|
||||
updateCompatOverrideScale(info);
|
||||
sendMessage(H.UPDATE_PACKAGE_COMPATIBILITY_INFO, ucd);
|
||||
}
|
||||
|
||||
|
||||
@@ -462,13 +462,30 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
|
||||
|
||||
/** @hide */
|
||||
public void scale(float scale) {
|
||||
mBounds.scale(scale);
|
||||
mMaxBounds.scale(scale);
|
||||
scaleBounds(scale, mBounds);
|
||||
scaleBounds(scale, mMaxBounds);
|
||||
if (mAppBounds != null) {
|
||||
mAppBounds.scale(scale);
|
||||
scaleBounds(scale, mAppBounds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Size based scaling. This avoid inconsistent length when rounding 4 sides.
|
||||
* E.g. left=12, right=18, scale=0.8. The scaled width can be:
|
||||
* int((right - left) * scale + 0.5) = int(4.8 + 0.5) = 5
|
||||
* But with rounding both left and right, the width will be inconsistent:
|
||||
* int(right * scale + 0.5) - int(left * scale + 0.5) = int(14.9) - int(10.1) = 4
|
||||
* @hide
|
||||
*/
|
||||
private static void scaleBounds(float scale, Rect bounds) {
|
||||
final int w = bounds.width();
|
||||
final int h = bounds.height();
|
||||
bounds.left = (int) (bounds.left * scale + .5f);
|
||||
bounds.top = (int) (bounds.top * scale + .5f);
|
||||
bounds.right = bounds.left + (int) (w * scale + .5f);
|
||||
bounds.bottom = bounds.top + (int) (h * scale + .5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the fields from delta into this Configuration object, keeping
|
||||
* track of which ones have changed. Any undefined fields in {@code delta}
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityThread.ActivityClientRecord;
|
||||
import android.app.ClientTransactionHandler;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
@@ -40,6 +41,7 @@ public class ActivityConfigurationChangeItem extends ActivityTransactionItem {
|
||||
|
||||
@Override
|
||||
public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
|
||||
CompatibilityInfo.applyOverrideScaleIfNeeded(mConfiguration);
|
||||
// Notify the client of an upcoming change in the token configuration. This ensures that
|
||||
// batches of config change items only process the newest configuration.
|
||||
client.updatePendingActivityConfiguration(token, mConfiguration);
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.annotation.Nullable;
|
||||
import android.app.ActivityThread.ActivityClientRecord;
|
||||
import android.app.ClientTransactionHandler;
|
||||
import android.app.ResultInfo;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.Trace;
|
||||
@@ -56,6 +57,7 @@ public class ActivityRelaunchItem extends ActivityTransactionItem {
|
||||
|
||||
@Override
|
||||
public void preExecute(ClientTransactionHandler client, IBinder token) {
|
||||
CompatibilityInfo.applyOverrideScaleIfNeeded(mConfig);
|
||||
mActivityClientRecord = client.prepareRelaunchActivity(token, mPendingResults,
|
||||
mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.app.servertransaction;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ClientTransactionHandler;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
@@ -34,6 +35,7 @@ public class ConfigurationChangeItem extends ClientTransactionItem {
|
||||
|
||||
@Override
|
||||
public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
|
||||
CompatibilityInfo.applyOverrideScaleIfNeeded(mConfiguration);
|
||||
client.updatePendingConfiguration(mConfiguration);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import android.app.ResultInfo;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.BaseBundle;
|
||||
import android.os.Bundle;
|
||||
@@ -81,6 +82,8 @@ public class LaunchActivityItem extends ClientTransactionItem {
|
||||
public void preExecute(ClientTransactionHandler client, IBinder token) {
|
||||
client.countLaunchingActivities(1);
|
||||
client.updateProcessState(mProcState, false);
|
||||
CompatibilityInfo.applyOverrideScaleIfNeeded(mCurConfig);
|
||||
CompatibilityInfo.applyOverrideScaleIfNeeded(mOverrideConfig);
|
||||
client.updatePendingConfiguration(mCurConfig);
|
||||
if (mActivityClientController != null) {
|
||||
ActivityClient.setActivityClientController(mActivityClientController);
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityThread.ActivityClientRecord;
|
||||
import android.app.ClientTransactionHandler;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
@@ -40,6 +41,7 @@ public class MoveToDisplayItem extends ActivityTransactionItem {
|
||||
|
||||
@Override
|
||||
public void preExecute(ClientTransactionHandler client, IBinder token) {
|
||||
CompatibilityInfo.applyOverrideScaleIfNeeded(mConfiguration);
|
||||
// Notify the client of an upcoming change in the token configuration. This ensures that
|
||||
// batches of config change items only process the newest configuration.
|
||||
client.updatePendingActivityConfiguration(token, mConfiguration);
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.os.Build.VERSION_CODES;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.MergedConfiguration;
|
||||
import android.view.InsetsSourceControl;
|
||||
import android.view.InsetsState;
|
||||
import android.view.MotionEvent;
|
||||
@@ -111,6 +112,9 @@ public class CompatibilityInfo implements Parcelable {
|
||||
*/
|
||||
public final float applicationInvertedScale;
|
||||
|
||||
/** The process level override inverted scale. See {@link #HAS_OVERRIDE_SCALING}. */
|
||||
private static float sOverrideInvertedScale = 1f;
|
||||
|
||||
@UnsupportedAppUsage
|
||||
@Deprecated
|
||||
public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw,
|
||||
@@ -125,6 +129,15 @@ public class CompatibilityInfo implements Parcelable {
|
||||
if (appInfo.targetSdkVersion < VERSION_CODES.O) {
|
||||
compatFlags |= NEEDS_COMPAT_RES;
|
||||
}
|
||||
if (overrideScale != 1.0f) {
|
||||
applicationScale = overrideScale;
|
||||
applicationInvertedScale = 1.0f / overrideScale;
|
||||
applicationDensity = (int) ((DisplayMetrics.DENSITY_DEVICE_STABLE
|
||||
* applicationInvertedScale) + .5f);
|
||||
mCompatibilityFlags = NEVER_NEEDS_COMPAT | HAS_OVERRIDE_SCALING;
|
||||
// Override scale has the highest priority. So ignore other compatibility attributes.
|
||||
return;
|
||||
}
|
||||
if (appInfo.requiresSmallestWidthDp != 0 || appInfo.compatibleWidthLimitDp != 0
|
||||
|| appInfo.largestWidthLimitDp != 0) {
|
||||
// New style screen requirements spec.
|
||||
@@ -254,13 +267,7 @@ public class CompatibilityInfo implements Parcelable {
|
||||
compatFlags |= NEVER_NEEDS_COMPAT;
|
||||
}
|
||||
|
||||
if (overrideScale != 1.0f) {
|
||||
applicationScale = overrideScale;
|
||||
applicationInvertedScale = 1.0f / overrideScale;
|
||||
applicationDensity = (int) ((DisplayMetrics.DENSITY_DEVICE_STABLE
|
||||
* applicationInvertedScale) + .5f);
|
||||
compatFlags |= HAS_OVERRIDE_SCALING;
|
||||
} else if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
|
||||
if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
|
||||
applicationDensity = DisplayMetrics.DENSITY_DEVICE;
|
||||
applicationScale = 1.0f;
|
||||
applicationInvertedScale = 1.0f;
|
||||
@@ -296,9 +303,14 @@ public class CompatibilityInfo implements Parcelable {
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public boolean isScalingRequired() {
|
||||
return (mCompatibilityFlags & (SCALING_REQUIRED | HAS_OVERRIDE_SCALING)) != 0;
|
||||
return (mCompatibilityFlags & SCALING_REQUIRED) != 0;
|
||||
}
|
||||
|
||||
|
||||
/** Returns {@code true} if {@link #sOverrideInvertedScale} should be set. */
|
||||
public boolean hasOverrideScaling() {
|
||||
return (mCompatibilityFlags & HAS_OVERRIDE_SCALING) != 0;
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public boolean supportsScreen() {
|
||||
return (mCompatibilityFlags&NEEDS_SCREEN_COMPAT) == 0;
|
||||
@@ -513,7 +525,19 @@ public class CompatibilityInfo implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
/** Applies the compatibility adjustment to the display metrics. */
|
||||
public void applyDisplayMetricsIfNeeded(DisplayMetrics inoutDm, boolean applyToSize) {
|
||||
if (hasOverrideScale()) {
|
||||
scaleDisplayMetrics(sOverrideInvertedScale, inoutDm, applyToSize);
|
||||
return;
|
||||
}
|
||||
if (!equals(DEFAULT_COMPATIBILITY_INFO)) {
|
||||
applyToDisplayMetrics(inoutDm);
|
||||
}
|
||||
}
|
||||
|
||||
public void applyToDisplayMetrics(DisplayMetrics inoutDm) {
|
||||
if (hasOverrideScale()) return;
|
||||
if (!supportsScreen()) {
|
||||
// This is a larger screen device and the app is not
|
||||
// compatible with large screens, so diddle it.
|
||||
@@ -524,18 +548,26 @@ public class CompatibilityInfo implements Parcelable {
|
||||
}
|
||||
|
||||
if (isScalingRequired()) {
|
||||
float invertedRatio = applicationInvertedScale;
|
||||
inoutDm.density = inoutDm.noncompatDensity * invertedRatio;
|
||||
inoutDm.densityDpi = (int)((inoutDm.noncompatDensityDpi * invertedRatio) + .5f);
|
||||
inoutDm.scaledDensity = inoutDm.noncompatScaledDensity * invertedRatio;
|
||||
inoutDm.xdpi = inoutDm.noncompatXdpi * invertedRatio;
|
||||
inoutDm.ydpi = inoutDm.noncompatYdpi * invertedRatio;
|
||||
scaleDisplayMetrics(applicationInvertedScale, inoutDm, true /* applyToSize */);
|
||||
}
|
||||
}
|
||||
|
||||
/** Scales the density of the given display metrics. */
|
||||
private static void scaleDisplayMetrics(float invertedRatio, DisplayMetrics inoutDm,
|
||||
boolean applyToSize) {
|
||||
inoutDm.density = inoutDm.noncompatDensity * invertedRatio;
|
||||
inoutDm.densityDpi = (int) ((inoutDm.noncompatDensityDpi * invertedRatio) + .5f);
|
||||
inoutDm.scaledDensity = inoutDm.noncompatScaledDensity * invertedRatio;
|
||||
inoutDm.xdpi = inoutDm.noncompatXdpi * invertedRatio;
|
||||
inoutDm.ydpi = inoutDm.noncompatYdpi * invertedRatio;
|
||||
if (applyToSize) {
|
||||
inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertedRatio + 0.5f);
|
||||
inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertedRatio + 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
public void applyToConfiguration(int displayDensity, Configuration inoutConfig) {
|
||||
if (hasOverrideScale()) return;
|
||||
if (!supportsScreen()) {
|
||||
// This is a larger screen device and the app is not
|
||||
// compatible with large screens, so we are forcing it to
|
||||
@@ -549,12 +581,45 @@ public class CompatibilityInfo implements Parcelable {
|
||||
}
|
||||
inoutConfig.densityDpi = displayDensity;
|
||||
if (isScalingRequired()) {
|
||||
float invertedRatio = applicationInvertedScale;
|
||||
inoutConfig.densityDpi = (int)((inoutConfig.densityDpi * invertedRatio) + .5f);
|
||||
inoutConfig.windowConfiguration.scale(invertedRatio);
|
||||
scaleConfiguration(applicationInvertedScale, inoutConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/** Scales the density and bounds of the given configuration. */
|
||||
public static void scaleConfiguration(float invertedRatio, Configuration inoutConfig) {
|
||||
inoutConfig.densityDpi = (int) ((inoutConfig.densityDpi * invertedRatio) + .5f);
|
||||
inoutConfig.windowConfiguration.scale(invertedRatio);
|
||||
}
|
||||
|
||||
/** @see #sOverrideInvertedScale */
|
||||
public static void applyOverrideScaleIfNeeded(Configuration config) {
|
||||
if (!hasOverrideScale()) return;
|
||||
scaleConfiguration(sOverrideInvertedScale, config);
|
||||
}
|
||||
|
||||
/** @see #sOverrideInvertedScale */
|
||||
public static void applyOverrideScaleIfNeeded(MergedConfiguration mergedConfig) {
|
||||
if (!hasOverrideScale()) return;
|
||||
scaleConfiguration(sOverrideInvertedScale, mergedConfig.getGlobalConfiguration());
|
||||
scaleConfiguration(sOverrideInvertedScale, mergedConfig.getOverrideConfiguration());
|
||||
scaleConfiguration(sOverrideInvertedScale, mergedConfig.getMergedConfiguration());
|
||||
}
|
||||
|
||||
/** Returns {@code true} if this process is in a environment with override scale. */
|
||||
private static boolean hasOverrideScale() {
|
||||
return sOverrideInvertedScale != 1f;
|
||||
}
|
||||
|
||||
/** @see #sOverrideInvertedScale */
|
||||
public static void setOverrideInvertedScale(float invertedRatio) {
|
||||
sOverrideInvertedScale = invertedRatio;
|
||||
}
|
||||
|
||||
/** @see #sOverrideInvertedScale */
|
||||
public static float getOverrideInvertedScale() {
|
||||
return sOverrideInvertedScale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the frame Rect for applications runs under compatibility mode.
|
||||
*
|
||||
@@ -632,6 +697,10 @@ public class CompatibilityInfo implements Parcelable {
|
||||
sb.append(applicationScale);
|
||||
sb.append("x");
|
||||
}
|
||||
if (hasOverrideScaling()) {
|
||||
sb.append(" overrideInvScale=");
|
||||
sb.append(applicationInvertedScale);
|
||||
}
|
||||
if (!supportsScreen()) {
|
||||
sb.append(" resizing");
|
||||
}
|
||||
|
||||
@@ -723,9 +723,9 @@ public final class DisplayInfo implements Parcelable {
|
||||
outMetrics.noncompatWidthPixels = outMetrics.widthPixels = width;
|
||||
outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
|
||||
|
||||
if (!compatInfo.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
|
||||
compatInfo.applyToDisplayMetrics(outMetrics);
|
||||
}
|
||||
// Apply to size if the configuration is EMPTY because the size is from real display info.
|
||||
final boolean applyToSize = configuration != null && appBounds == null;
|
||||
compatInfo.applyDisplayMetricsIfNeeded(outMetrics, applyToSize);
|
||||
}
|
||||
|
||||
// For debugging purposes
|
||||
|
||||
@@ -1787,6 +1787,7 @@ public final class ViewRootImpl implements ViewParent,
|
||||
|
||||
final ClientWindowFrames frames = (ClientWindowFrames) args.arg1;
|
||||
final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg2;
|
||||
CompatibilityInfo.applyOverrideScaleIfNeeded(mergedConfiguration);
|
||||
final boolean forceNextWindowRelayout = args.argi1 != 0;
|
||||
final int displayId = args.argi3;
|
||||
final int resizeMode = args.argi5;
|
||||
@@ -8242,6 +8243,7 @@ public final class ViewRootImpl implements ViewParent,
|
||||
mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
|
||||
}
|
||||
mInvSizeCompatScale = 1f / mTmpFrames.sizeCompatScale;
|
||||
CompatibilityInfo.applyOverrideScaleIfNeeded(mPendingMergedConfiguration);
|
||||
mInsetsController.onStateChanged(mTempInsets);
|
||||
mInsetsController.onControlsChanged(mTempControls);
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.app.ActivityThread;
|
||||
import android.app.IWindowToken;
|
||||
import android.app.ResourcesManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.inputmethodservice.AbstractInputMethodService;
|
||||
import android.os.Build;
|
||||
@@ -221,6 +222,7 @@ public class WindowTokenClient extends IWindowToken.Stub {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
CompatibilityInfo.applyOverrideScaleIfNeeded(newConfig);
|
||||
final boolean displayChanged;
|
||||
final boolean shouldUpdateResources;
|
||||
final int diff;
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.annotation.Nullable;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.ActivityThread.ActivityClientRecord;
|
||||
import android.app.Application;
|
||||
import android.app.IApplicationThread;
|
||||
import android.app.PictureInPictureParams;
|
||||
import android.app.ResourcesManager;
|
||||
@@ -46,6 +47,7 @@ import android.app.servertransaction.ResumeActivityItem;
|
||||
import android.app.servertransaction.StopActivityItem;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.CompatibilityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Rect;
|
||||
@@ -177,6 +179,85 @@ public class ActivityThreadTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrideScale() throws Exception {
|
||||
final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
|
||||
final Application app = activity.getApplication();
|
||||
final ActivityThread activityThread = activity.getActivityThread();
|
||||
final IApplicationThread appThread = activityThread.getApplicationThread();
|
||||
final DisplayMetrics originalAppMetrics = new DisplayMetrics();
|
||||
originalAppMetrics.setTo(app.getResources().getDisplayMetrics());
|
||||
final Configuration originalAppConfig =
|
||||
new Configuration(app.getResources().getConfiguration());
|
||||
final DisplayMetrics originalActivityMetrics = new DisplayMetrics();
|
||||
originalActivityMetrics.setTo(activity.getResources().getDisplayMetrics());
|
||||
final Configuration originalActivityConfig =
|
||||
new Configuration(activity.getResources().getConfiguration());
|
||||
|
||||
final Configuration newConfig = new Configuration(originalAppConfig);
|
||||
newConfig.seq = BASE_SEQ + 1;
|
||||
newConfig.smallestScreenWidthDp++;
|
||||
|
||||
final float originalScale = CompatibilityInfo.getOverrideInvertedScale();
|
||||
float scale = 0.5f;
|
||||
CompatibilityInfo.setOverrideInvertedScale(scale);
|
||||
try {
|
||||
// Send process level config change.
|
||||
ClientTransaction transaction = newTransaction(activityThread, null);
|
||||
transaction.addCallback(ConfigurationChangeItem.obtain(new Configuration(newConfig)));
|
||||
appThread.scheduleTransaction(transaction);
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertScreenScale(scale, app, originalAppConfig, originalAppMetrics);
|
||||
// The activity's config doesn't change because ConfigurationChangeItem is process level
|
||||
// that won't affect activity's override config.
|
||||
assertEquals(originalActivityConfig.densityDpi,
|
||||
activity.getResources().getConfiguration().densityDpi);
|
||||
|
||||
scale = 0.8f;
|
||||
CompatibilityInfo.setOverrideInvertedScale(scale);
|
||||
// Send activity level config change.
|
||||
newConfig.seq++;
|
||||
newConfig.smallestScreenWidthDp++;
|
||||
transaction = newTransaction(activityThread, activity.getActivityToken());
|
||||
transaction.addCallback(ActivityConfigurationChangeItem.obtain(
|
||||
new Configuration(newConfig)));
|
||||
appThread.scheduleTransaction(transaction);
|
||||
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
|
||||
|
||||
assertScreenScale(scale, activity, originalActivityConfig, originalActivityMetrics);
|
||||
} finally {
|
||||
CompatibilityInfo.setOverrideInvertedScale(originalScale);
|
||||
InstrumentationRegistry.getInstrumentation().runOnMainSync(
|
||||
() -> restoreConfig(activityThread, originalAppConfig));
|
||||
}
|
||||
assertScreenScale(originalScale, app, originalAppConfig, originalAppMetrics);
|
||||
}
|
||||
|
||||
private static void assertScreenScale(float scale, Context context,
|
||||
Configuration origConfig, DisplayMetrics origMetrics) {
|
||||
final int expectedDpi = (int) (origConfig.densityDpi * scale + .5f);
|
||||
final float expectedDensity = origMetrics.density * scale;
|
||||
final int expectedWidthPixels = (int) (origMetrics.widthPixels * scale + .5f);
|
||||
final int expectedHeightPixels = (int) (origMetrics.heightPixels * scale + .5f);
|
||||
final Configuration expectedConfig = new Configuration(origConfig);
|
||||
CompatibilityInfo.scaleConfiguration(scale, expectedConfig);
|
||||
final Rect expectedBounds = expectedConfig.windowConfiguration.getBounds();
|
||||
final Rect expectedAppBounds = expectedConfig.windowConfiguration.getAppBounds();
|
||||
final Rect expectedMaxBounds = expectedConfig.windowConfiguration.getMaxBounds();
|
||||
|
||||
final Configuration currentConfig = context.getResources().getConfiguration();
|
||||
final DisplayMetrics currentMetrics = context.getResources().getDisplayMetrics();
|
||||
assertEquals(expectedDpi, currentConfig.densityDpi);
|
||||
assertEquals(expectedDpi, currentMetrics.densityDpi);
|
||||
assertEquals(expectedDensity, currentMetrics.density, 0.001f);
|
||||
assertEquals(expectedWidthPixels, currentMetrics.widthPixels);
|
||||
assertEquals(expectedHeightPixels, currentMetrics.heightPixels);
|
||||
assertEquals(expectedBounds, currentConfig.windowConfiguration.getBounds());
|
||||
assertEquals(expectedAppBounds, currentConfig.windowConfiguration.getAppBounds());
|
||||
assertEquals(expectedMaxBounds, currentConfig.windowConfiguration.getMaxBounds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleActivityConfigurationChanged() {
|
||||
final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
|
||||
@@ -459,19 +540,17 @@ public class ActivityThreadTest {
|
||||
} finally {
|
||||
// Make sure to reset the process config to prevent side effects to other
|
||||
// tests.
|
||||
Configuration activityThreadConfig = activityThread.getConfiguration();
|
||||
activityThreadConfig.seq = originalAppConfig.seq - 1;
|
||||
|
||||
Configuration resourceManagerConfig = ResourcesManager.getInstance()
|
||||
.getConfiguration();
|
||||
resourceManagerConfig.seq = originalAppConfig.seq - 1;
|
||||
|
||||
activityThread.updatePendingConfiguration(originalAppConfig);
|
||||
activityThread.handleConfigurationChanged(originalAppConfig);
|
||||
restoreConfig(activityThread, originalAppConfig);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void restoreConfig(ActivityThread thread, Configuration originalConfig) {
|
||||
thread.getConfiguration().seq = originalConfig.seq - 1;
|
||||
ResourcesManager.getInstance().getConfiguration().seq = originalConfig.seq - 1;
|
||||
thread.handleConfigurationChanged(originalConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActivityOrientationChanged_DoesntOverrideVirtualDisplayOrientation() {
|
||||
final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
|
||||
|
||||
@@ -671,11 +671,9 @@ public class WindowStateTests extends WindowTestsBase {
|
||||
verify(t, never()).setMatrix(any(), anyInt(), anyInt(), anyInt(), anyInt());
|
||||
|
||||
// According to "dp * density / 160 = px", density is scaled and the size in dp is the same.
|
||||
final CompatibilityInfo compatInfo = cmp.compatibilityInfoForPackageLocked(
|
||||
mContext.getApplicationInfo());
|
||||
final Configuration winConfig = w.getConfiguration();
|
||||
final Configuration clientConfig = new Configuration(w.getConfiguration());
|
||||
compatInfo.applyToConfiguration(clientConfig.densityDpi, clientConfig);
|
||||
CompatibilityInfo.scaleConfiguration(w.mInvGlobalScale, clientConfig);
|
||||
|
||||
assertEquals(winConfig.screenWidthDp, clientConfig.screenWidthDp);
|
||||
assertEquals(winConfig.screenHeightDp, clientConfig.screenHeightDp);
|
||||
|
||||
Reference in New Issue
Block a user