public static final int FLAG_ALLOW_BACKUP = 1<<10;
/**
+ * Indicates that the application supports any densities;
+ * {@hide}
+ */
+ public static final int ANY_DENSITY = -1;
+ private static final int[] ANY_DENSITIES_ARRAY = { ANY_DENSITY };
+
+ /**
* Flags associated with the application. Any combination of
* {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE},
* {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and
}
return null;
}
+
+ /**
+ * Disable compatibility mode
+ *
+ * @hide
+ */
+ public void disableCompatibilityMode() {
+ expandable = true;
+ supportsDensities = ANY_DENSITIES_ARRAY;
+ }
}
public final float mApplicationInvertedScale;
/**
- *
* A boolean flag to indicates that the application can expand over the original size.
+ * The flag is set to true if
+ * 1) Application declares its expandable in manifest file using <expandable /> or
+ * 2) The screen size is same as (320 x 480) * density.
*/
- public final boolean mExpandable;
+ public boolean mExpandable;
+
+ /**
+ * A expandable flag in the configuration.
+ */
+ public final boolean mConfiguredExpandable;
/**
* A boolean flag to tell if the application needs scaling (when mApplicationScale != 1.0f)
public final boolean mScalingRequired;
public CompatibilityInfo(ApplicationInfo appInfo) {
- // A temp workaround to fix rotation issue.
- // mExpandable = appInfo.expandable;
- mExpandable = true;
+ mExpandable = mConfiguredExpandable = appInfo.expandable;
+
float packageDensityScale = -1.0f;
if (appInfo.supportsDensities != null) {
int minDiff = Integer.MAX_VALUE;
for (int density : appInfo.supportsDensities) {
+ if (density == ApplicationInfo.ANY_DENSITY) {
+ packageDensityScale = 1.0f;
+ break;
+ }
int tmpDiff = Math.abs(DisplayMetrics.DEVICE_DENSITY - density);
if (tmpDiff == 0) {
packageDensityScale = 1.0f;
private CompatibilityInfo() {
mApplicationScale = mApplicationInvertedScale = 1.0f;
- mExpandable = true;
+ mExpandable = mConfiguredExpandable = true;
mScalingRequired = false;
}
PluralRules mPluralRule;
private final CompatibilityInfo mCompatibilityInfo;
-
+
private static final SparseArray<Object> EMPTY_ARRAY = new SparseArray<Object>() {
@Override
public void put(int k, Object o) {
return array;
}
-
+
/**
* Store the newly updated configuration.
*/
}
if (metrics != null) {
mMetrics.setTo(metrics);
- mMetrics.updateMetrics(mCompatibilityInfo, mConfiguration);
+ mMetrics.updateMetrics(mCompatibilityInfo, mConfiguration.orientation);
}
mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
/**
+ * If 0, the compatibility mode is off for all applications.
+ * If 1, older applications run under compatibility mode.
+ * TODO: remove this settings before code freeze (bug/1907571)
+ * @hide
+ */
+ public static final String COMPATIBILITY_MODE = "compatibility_mode";
+
+ /**
* The screen backlight brightness between 0 and 255.
*/
public static final String SCREEN_BRIGHTNESS = "screen_brightness";
}
/**
- * Update the display metrics based on the compatibility info and configuration.
+ * Update the display metrics based on the compatibility info and orientation
* {@hide}
*/
- public void updateMetrics(CompatibilityInfo compatibilityInfo, Configuration configuration) {
+ public void updateMetrics(CompatibilityInfo compatibilityInfo, int orientation) {
if (compatibilityInfo.mScalingRequired) {
float invertedRatio = compatibilityInfo.mApplicationInvertedScale;
density *= invertedRatio;
widthPixels *= invertedRatio;
heightPixels *= invertedRatio;
}
- if (!compatibilityInfo.mExpandable) {
+ if (!compatibilityInfo.mConfiguredExpandable) {
// Note: this assume that configuration is updated before calling
// updateMetrics method.
int defaultWidth;
int defaultHeight;
- switch (configuration.orientation) {
+ switch (orientation) {
case Configuration.ORIENTATION_LANDSCAPE: {
defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density);
defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density);
break;
}
- case Configuration.ORIENTATION_UNDEFINED:
case Configuration.ORIENTATION_PORTRAIT:
case Configuration.ORIENTATION_SQUARE:
default: {
defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density);
defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density);
+ break;
+ }
+ case Configuration.ORIENTATION_UNDEFINED: {
+ // don't change
+ return;
}
}
- // adjust the size only when the device's screen is bigger.
- if (defaultWidth < widthPixels) {
- widthPixels = defaultWidth;
- }
- if (defaultHeight < heightPixels) {
- heightPixels = defaultHeight;
+
+ if (defaultWidth == widthPixels && defaultHeight == heightPixels) {
+ // the screen size is same as expected size. make it expandable
+ compatibilityInfo.mExpandable = true;
+ } else {
+ compatibilityInfo.mExpandable = false;
+ // adjust the size only when the device's screen is bigger.
+ if (defaultWidth < widthPixels) {
+ widthPixels = defaultWidth;
+ }
+ if (defaultHeight < heightPixels) {
+ heightPixels = defaultHeight;
+ }
}
}
}
boolean mIsAnimating;
private CompatibilityInfo mCompatibilityInfo;
- private int[] mWindowLayoutParamsBackup = null;
final View.AttachInfo mAttachInfo;
if (mView == null) {
mView = view;
mWindowAttributes.copyFrom(attrs);
- mCompatibilityInfo =
- mView.getContext().getResources().getCompatibilityInfo();
- if (mCompatibilityInfo.mScalingRequired) {
- mWindowLayoutParamsBackup = new int[4];
+ mCompatibilityInfo = mView.getContext().getResources().getCompatibilityInfo();
+ boolean restore = false;
+ if (mCompatibilityInfo.mScalingRequired || !mCompatibilityInfo.mExpandable) {
+ restore = true;
+ mWindowAttributes.backup();
}
if (!mCompatibilityInfo.mExpandable) {
adjustWindowAttributesForCompatibleMode(mWindowAttributes);
unscheduleTraversals();
throw new RuntimeException("Adding window failed", e);
}
+
+ if (restore) {
+ mWindowAttributes.restore();
+ }
+
if (mCompatibilityInfo.mScalingRequired) {
mAttachInfo.mContentInsets.scale(
mCompatibilityInfo.mApplicationInvertedScale);
} else {
didFinish = false;
}
- if (event != null && mCompatibilityInfo.mScalingRequired) {
- event.scale(mCompatibilityInfo.mApplicationInvertedScale);
- }
if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
boolean restore = false;
float appScale = mCompatibilityInfo.mApplicationScale;
boolean scalingRequired = mCompatibilityInfo.mScalingRequired;
-
if (params != null && !mCompatibilityInfo.mExpandable) {
+ restore = true;
+ params.backup();
adjustWindowAttributesForCompatibleMode(params);
}
if (params != null && scalingRequired) {
+ if (!restore) params.backup();
restore = true;
- params.scale(appScale, mWindowLayoutParamsBackup);
+ params.scale(appScale);
}
int relayoutResult = sWindowSession.relayout(
mWindow, params,
viewVisibility, insetsPending, mWinFrame,
mPendingContentInsets, mPendingVisibleInsets, mSurface);
if (restore) {
- params.restore(mWindowLayoutParamsBackup);
+ params.restore();
}
if (scalingRequired) {
float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
if (attrs.width == ViewGroup.LayoutParams.FILL_PARENT) {
attrs.width = metrics.widthPixels;
attrs.gravity |= Gravity.CENTER_HORIZONTAL;
+ mWindowAttributesChanged = attrs == mWindowAttributes;
}
if (attrs.height == ViewGroup.LayoutParams.FILL_PARENT) {
attrs.height = metrics.heightPixels;
+ attrs.gravity |= Gravity.TOP;
+ mWindowAttributesChanged = attrs == mWindowAttributes;
}
if (DEBUG_LAYOUT) {
- Log.d(TAG, "Attributes fixed for compatibility : " + attrs);
+ Log.d(TAG, "Adjusted Attributes for compatibility : " + attrs);
}
}
}
public static final int SCREEN_ORIENTATION_CHANGED = 1<<10;
public static final int SCREEN_BRIGHTNESS_CHANGED = 1<<11;
+ // internal buffer to backup/restore parameters under compatibility mode.
+ private int[] mCompatibilityParamsBackup = null;
+
public final int copyFrom(LayoutParams o) {
int changes = 0;
/**
* Scale the layout params' coordinates and size.
- * Returns the original info as a backup so that the caller can
- * restore the layout params;
- */
- void scale(float scale, int[] backup) {
- if (scale != 1.0f) {
- backup[0] = x;
- backup[1] = y;
- x *= scale;
- y *= scale;
- if (width > 0) {
- backup[2] = width;
- width *= scale;
- }
- if (height > 0) {
- backup[3] = height;
- height *= scale;
- }
+ */
+ void scale(float scale) {
+ x *= scale;
+ y *= scale;
+ if (width > 0) {
+ width *= scale;
+ }
+ if (height > 0) {
+ height *= scale;
}
}
/**
- * Restore the layout params' coordinates and size.
- */
- void restore(int[] backup) {
- x = backup[0];
- y = backup[1];
- if (width > 0) {
- width = backup[2];
+ * Backup the layout parameters used in compatibility mode.
+ * @see LayoutParams#restore()
+ */
+ void backup() {
+ int[] backup = mCompatibilityParamsBackup;
+ if (backup == null) {
+ // we backup 5 elements, x, y, width, height and gravity.
+ backup = mCompatibilityParamsBackup = new int[5];
}
- if (height > 0) {
+ backup[0] = x;
+ backup[1] = y;
+ backup[2] = width;
+ backup[3] = height;
+ backup[4] = gravity;
+ }
+
+ /**
+ * Restore the layout params' coordinates, size and gravity
+ * @see LayoutParams#backup()
+ */
+ void restore() {
+ int[] backup = mCompatibilityParamsBackup;
+ if (backup != null) {
+ x = backup[0];
+ y = backup[1];
+ width = backup[2];
height = backup[3];
+ gravity = backup[4];
}
}
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
final ResolveInfo mResolveInfo = new ResolveInfo();
ComponentName mResolveComponentName;
PackageParser.Package mPlatformPackage;
+ private boolean mCompatibilityModeEnabled = true;
public static final IPackageManager main(Context context, boolean factoryTest) {
PackageManagerService m = new PackageManagerService(context, factoryTest);
} // synchronized (mPackages)
} // synchronized (mInstallLock)
}
-
+
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
+ ": " + p);
if (p != null) {
// Note: isEnabledLP() does not apply here - always return info
- return PackageParser.generateApplicationInfo(p, flags);
+ ApplicationInfo appInfo = PackageParser.generateApplicationInfo(p, flags);
+ if (!mCompatibilityModeEnabled) {
+ appInfo.disableCompatibilityMode();
+ }
+ return appInfo;
}
if ("android".equals(packageName)||"system".equals(packageName)) {
return mAndroidApplication;
public ActivityInfo getActivityInfo(ComponentName component, int flags) {
synchronized (mPackages) {
PackageParser.Activity a = mActivities.mActivities.get(component);
- if (Config.LOGV) Log.v(
- TAG, "getActivityInfo " + component + ": " + a);
+
+ if (Config.LOGV) Log.v(TAG, "getActivityInfo " + component + ": " + a);
if (a != null && mSettings.isEnabledLP(a.info, flags)) {
- return PackageParser.generateActivityInfo(a, flags);
+ ActivityInfo ainfo = PackageParser.generateActivityInfo(a, flags);
+ if (ainfo != null && (flags & PackageManager.GET_EXPANDABLE) != 0) {
+ ApplicationInfo appInfo = getApplicationInfo(component.getPackageName(),
+ PackageManager.GET_EXPANDABLE | PackageManager.GET_SUPPORTS_DENSITIES);
+ if (appInfo != null && !appInfo.expandable) {
+ // Check if the screen size is same as what the application expect.
+ CompatibilityInfo info = new CompatibilityInfo(appInfo);
+ DisplayMetrics metrics = new DisplayMetrics();
+ metrics.setTo(mMetrics);
+ int orientation = mMetrics.widthPixels > mMetrics.heightPixels ?
+ Configuration.ORIENTATION_LANDSCAPE :
+ Configuration.ORIENTATION_PORTRAIT;
+ metrics.updateMetrics(info, orientation);
+ if (!info.mExpandable) {
+ // Don't allow an app that cannot expand to handle rotation.
+ ainfo.configChanges &= ~ ActivityInfo.CONFIG_ORIENTATION;
+ } else {
+ appInfo.expandable = true;
+ }
+ if (DEBUG_SETTINGS) {
+ Log.d(TAG, "component=" + component +
+ ", expandable:" + appInfo.expandable);
+ }
+ }
+ }
+ return ainfo;
}
if (mResolveComponentName.equals(component)) {
return mResolveActivity;
public void systemReady() {
mSystemReady = true;
+
+ // Read the compatibilty setting when the system is ready.
+ mCompatibilityModeEnabled = android.provider.Settings.System.getInt(
+ mContext.getContentResolver(),
+ android.provider.Settings.System.COMPATIBILITY_MODE, 1) == 1;
+ if (DEBUG_SETTINGS) {
+ Log.d(TAG, "compatibility mode:" + mCompatibilityModeEnabled);
+ }
}
public boolean isSafeMode() {