diff options
Diffstat (limited to 'core/java/android')
-rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 23 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 167 | ||||
-rw-r--r-- | core/java/android/app/ApplicationThreadNative.java | 65 | ||||
-rw-r--r-- | core/java/android/app/ContextImpl.java | 4 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.java | 4 | ||||
-rw-r--r-- | core/java/android/app/IApplicationThread.java | 23 | ||||
-rw-r--r-- | core/java/android/app/LoadedApk.java | 10 | ||||
-rw-r--r-- | core/java/android/content/res/CompatibilityInfo.java | 358 | ||||
-rw-r--r-- | core/java/android/content/res/Configuration.java | 21 | ||||
-rwxr-xr-x | core/java/android/content/res/Resources.java | 31 | ||||
-rw-r--r-- | core/java/android/util/DisplayMetrics.java | 108 | ||||
-rw-r--r-- | core/java/android/view/Display.java | 3 | ||||
-rw-r--r-- | core/java/android/view/WindowManagerPolicy.java | 12 |
13 files changed, 485 insertions, 344 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 6426635..11e9975 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1398,6 +1398,16 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION: + { + data.enforceInterface(IActivityManager.descriptor); + String pkg = data.readString(); + boolean enabled = data.readInt() != 0; + setPackageScreenCompatMode(pkg, enabled); + reply.writeNoException(); + return true; + } + } return super.onTransact(code, data, reply, flags); @@ -3142,5 +3152,18 @@ class ActivityManagerProxy implements IActivityManager return result; } + public void setPackageScreenCompatMode(String packageName, boolean compatEnabled) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeString(packageName); + data.writeInt(compatEnabled ? 1 : 0); + mRemote.transact(SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION, data, reply, 0); + reply.readException(); + reply.recycle(); + data.recycle(); + } + private IBinder mRemote; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index bd83762..67e8839 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -202,7 +202,7 @@ public final class ActivityThread { Bundle mCoreSettings = null; - private static final class ActivityClientRecord { + static final class ActivityClientRecord { IBinder token; int ident; Intent intent; @@ -220,6 +220,7 @@ public final class ActivityThread { ActivityClientRecord nextIdle; ActivityInfo activityInfo; + CompatibilityInfo compatInfo; LoadedApk packageInfo; List<ResultInfo> pendingResults; @@ -260,7 +261,7 @@ public final class ActivityThread { } } - private final class ProviderClientRecord implements IBinder.DeathRecipient { + final class ProviderClientRecord implements IBinder.DeathRecipient { final String mName; final IContentProvider mProvider; final ContentProvider mLocalProvider; @@ -277,7 +278,7 @@ public final class ActivityThread { } } - private static final class NewIntentData { + static final class NewIntentData { List<Intent> intents; IBinder token; public String toString() { @@ -285,7 +286,7 @@ public final class ActivityThread { } } - private static final class ReceiverData extends BroadcastReceiver.PendingResult { + static final class ReceiverData extends BroadcastReceiver.PendingResult { public ReceiverData(Intent intent, int resultCode, String resultData, Bundle resultExtras, boolean ordered, boolean sticky, IBinder token) { super(resultCode, resultData, resultExtras, TYPE_COMPONENT, ordered, sticky, token); @@ -294,6 +295,7 @@ public final class ActivityThread { Intent intent; ActivityInfo info; + CompatibilityInfo compatInfo; public String toString() { return "ReceiverData{intent=" + intent + " packageName=" + info.packageName + " resultCode=" + getResultCode() @@ -302,8 +304,9 @@ public final class ActivityThread { } } - private static final class CreateBackupAgentData { + static final class CreateBackupAgentData { ApplicationInfo appInfo; + CompatibilityInfo compatInfo; int backupMode; public String toString() { return "CreateBackupAgentData{appInfo=" + appInfo @@ -312,9 +315,10 @@ public final class ActivityThread { } } - private static final class CreateServiceData { + static final class CreateServiceData { IBinder token; ServiceInfo info; + CompatibilityInfo compatInfo; Intent intent; public String toString() { return "CreateServiceData{token=" + token + " className=" @@ -323,7 +327,7 @@ public final class ActivityThread { } } - private static final class BindServiceData { + static final class BindServiceData { IBinder token; Intent intent; boolean rebind; @@ -332,7 +336,7 @@ public final class ActivityThread { } } - private static final class ServiceArgsData { + static final class ServiceArgsData { IBinder token; int startId; int flags; @@ -343,7 +347,7 @@ public final class ActivityThread { } } - private static final class AppBindData { + static final class AppBindData { LoadedApk info; String processName; ApplicationInfo appInfo; @@ -355,13 +359,14 @@ public final class ActivityThread { int debugMode; boolean restrictedBackupMode; Configuration config; + CompatibilityInfo compatInfo; boolean handlingProfiling; public String toString() { return "AppBindData{appInfo=" + appInfo + "}"; } } - private static final class DumpComponentInfo { + static final class DumpComponentInfo { FileDescriptor fd; IBinder token; String prefix; @@ -369,7 +374,7 @@ public final class ActivityThread { boolean dumped; } - private static final class ResultData { + static final class ResultData { IBinder token; List<ResultInfo> results; public String toString() { @@ -377,22 +382,27 @@ public final class ActivityThread { } } - private static final class ContextCleanupInfo { + static final class ContextCleanupInfo { ContextImpl context; String what; String who; } - private static final class ProfilerControlData { + static final class ProfilerControlData { String path; ParcelFileDescriptor fd; } - private static final class DumpHeapData { + static final class DumpHeapData { String path; ParcelFileDescriptor fd; } + static final class UpdateCompatibilityData { + String pkg; + CompatibilityInfo info; + } + private final class ApplicationThread extends ApplicationThreadNative { private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s"; private static final String ONE_COUNT_COLUMN = "%17s %8d"; @@ -443,7 +453,8 @@ public final class ActivityThread { // we use token to identify this activity without having to send the // activity itself back to the activity manager. (matters more with ipc) public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, - ActivityInfo info, Bundle state, List<ResultInfo> pendingResults, + ActivityInfo info, CompatibilityInfo compatInfo, Bundle state, + List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) { ActivityClientRecord r = new ActivityClientRecord(); @@ -451,6 +462,7 @@ public final class ActivityThread { r.ident = ident; r.intent = intent; r.activityInfo = info; + r.compatInfo = compatInfo; r.state = state; r.pendingResults = pendingResults; @@ -484,33 +496,40 @@ public final class ActivityThread { } public final void scheduleReceiver(Intent intent, ActivityInfo info, - int resultCode, String data, Bundle extras, boolean sync) { + CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras, + boolean sync) { ReceiverData r = new ReceiverData(intent, resultCode, data, extras, sync, false, mAppThread.asBinder()); r.info = info; + r.compatInfo = compatInfo; queueOrSendMessage(H.RECEIVER, r); } - public final void scheduleCreateBackupAgent(ApplicationInfo app, int backupMode) { + public final void scheduleCreateBackupAgent(ApplicationInfo app, + CompatibilityInfo compatInfo, int backupMode) { CreateBackupAgentData d = new CreateBackupAgentData(); d.appInfo = app; + d.compatInfo = compatInfo; d.backupMode = backupMode; queueOrSendMessage(H.CREATE_BACKUP_AGENT, d); } - public final void scheduleDestroyBackupAgent(ApplicationInfo app) { + public final void scheduleDestroyBackupAgent(ApplicationInfo app, + CompatibilityInfo compatInfo) { CreateBackupAgentData d = new CreateBackupAgentData(); d.appInfo = app; + d.compatInfo = compatInfo; queueOrSendMessage(H.DESTROY_BACKUP_AGENT, d); } public final void scheduleCreateService(IBinder token, - ServiceInfo info) { + ServiceInfo info, CompatibilityInfo compatInfo) { CreateServiceData s = new CreateServiceData(); s.token = token; s.info = info; + s.compatInfo = compatInfo; queueOrSendMessage(H.CREATE_SERVICE, s); } @@ -553,7 +572,8 @@ public final class ActivityThread { ComponentName instrumentationName, String profileFile, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, int debugMode, boolean isRestrictedBackupMode, Configuration config, - Map<String, IBinder> services, Bundle coreSettings) { + CompatibilityInfo compatInfo, Map<String, IBinder> services, + Bundle coreSettings) { if (services != null) { // Setup the service cache in the ServiceManager @@ -573,6 +593,7 @@ public final class ActivityThread { data.debugMode = debugMode; data.restrictedBackupMode = isRestrictedBackupMode; data.config = config; + data.compatInfo = compatInfo; queueOrSendMessage(H.BIND_APPLICATION, data); } @@ -903,6 +924,13 @@ public final class ActivityThread { public void setCoreSettings(Bundle coreSettings) { queueOrSendMessage(H.SET_CORE_SETTINGS, coreSettings); } + + public void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) { + UpdateCompatibilityData ucd = new UpdateCompatibilityData(); + ucd.pkg = pkg; + ucd.info = info; + queueOrSendMessage(H.UPDATE_PACKAGE_COMPATIBILITY_INFO, ucd); + } } private final class H extends Handler { @@ -945,6 +973,7 @@ public final class ActivityThread { public static final int DUMP_ACTIVITY = 136; public static final int SLEEPING = 137; public static final int SET_CORE_SETTINGS = 138; + public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139; String codeToString(int code) { if (DEBUG_MESSAGES) { switch (code) { @@ -987,6 +1016,7 @@ public final class ActivityThread { case DUMP_ACTIVITY: return "DUMP_ACTIVITY"; case SLEEPING: return "SLEEPING"; case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS"; + case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO"; } } return "(unknown)"; @@ -998,7 +1028,7 @@ public final class ActivityThread { ActivityClientRecord r = (ActivityClientRecord)msg.obj; r.packageInfo = getPackageInfoNoCheck( - r.activityInfo.applicationInfo); + r.activityInfo.applicationInfo, r.compatInfo); handleLaunchActivity(r, null); } break; case RELAUNCH_ACTIVITY: { @@ -1072,7 +1102,7 @@ public final class ActivityThread { handleRequestThumbnail((IBinder)msg.obj); break; case CONFIGURATION_CHANGED: - handleConfigurationChanged((Configuration)msg.obj); + handleConfigurationChanged((Configuration)msg.obj, null); break; case CLEAN_UP_CONTEXT: ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj; @@ -1125,6 +1155,8 @@ public final class ActivityThread { case SET_CORE_SETTINGS: handleSetCoreSettings((Bundle) msg.obj); break; + case UPDATE_PACKAGE_COMPATIBILITY_INFO: + handleUpdatePackageCompatibilityInfo((UpdateCompatibilityData)msg.obj); } if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what); } @@ -1335,7 +1367,8 @@ public final class ActivityThread { return mH; } - public final LoadedApk getPackageInfo(String packageName, int flags) { + public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo, + int flags) { synchronized (mPackages) { WeakReference<LoadedApk> ref; if ((flags&Context.CONTEXT_INCLUDE_CODE) != 0) { @@ -1369,13 +1402,14 @@ public final class ActivityThread { } if (ai != null) { - return getPackageInfo(ai, flags); + return getPackageInfo(ai, compatInfo, flags); } return null; } - public final LoadedApk getPackageInfo(ApplicationInfo ai, int flags) { + public final LoadedApk getPackageInfo(ApplicationInfo ai, CompatibilityInfo compatInfo, + int flags) { boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0; boolean securityViolation = includeCode && ai.uid != 0 && ai.uid != Process.SYSTEM_UID && (mBoundApplication != null @@ -1394,14 +1428,27 @@ public final class ActivityThread { throw new SecurityException(msg); } } - return getPackageInfo(ai, null, securityViolation, includeCode); + return getPackageInfo(ai, compatInfo, null, securityViolation, includeCode); } - public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai) { - return getPackageInfo(ai, null, false, true); + public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai, + CompatibilityInfo compatInfo) { + return getPackageInfo(ai, compatInfo, null, false, true); } - private final LoadedApk getPackageInfo(ApplicationInfo aInfo, + public final LoadedApk peekPackageInfo(String packageName, boolean includeCode) { + synchronized (mPackages) { + WeakReference<LoadedApk> ref; + if (includeCode) { + ref = mPackages.get(packageName); + } else { + ref = mResourcePackages.get(packageName); + } + return ref != null ? ref.get() : null; + } + } + + private final LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo, ClassLoader baseLoader, boolean securityViolation, boolean includeCode) { synchronized (mPackages) { WeakReference<LoadedApk> ref; @@ -1419,7 +1466,7 @@ public final class ActivityThread { ? mBoundApplication.processName : null) + ")"); packageInfo = - new LoadedApk(this, aInfo, this, baseLoader, + new LoadedApk(this, aInfo, compatInfo, this, baseLoader, securityViolation, includeCode && (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0); if (includeCode) { @@ -1476,7 +1523,8 @@ public final class ActivityThread { if (mSystemContext == null) { ContextImpl context = ContextImpl.createSystemContext(this); - LoadedApk info = new LoadedApk(this, "android", context, null); + LoadedApk info = new LoadedApk(this, "android", context, null, + CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO); context.init(info, null, this); context.getResources().updateConfiguration( getConfiguration(), getDisplayMetricsLocked(false)); @@ -1491,7 +1539,8 @@ public final class ActivityThread { public void installSystemApplicationInfo(ApplicationInfo info) { synchronized (this) { ContextImpl context = getSystemContext(); - context.init(new LoadedApk(this, "android", context, info), null, this); + context.init(new LoadedApk(this, "android", context, info, + new CompatibilityInfo(info, 0, false)), null, this); } } @@ -1641,7 +1690,7 @@ public final class ActivityThread { ActivityInfo aInfo = r.activityInfo; if (r.packageInfo == null) { - r.packageInfo = getPackageInfo(aInfo.applicationInfo, + r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE); } @@ -1865,7 +1914,7 @@ public final class ActivityThread { String component = data.intent.getComponent().getClassName(); LoadedApk packageInfo = getPackageInfoNoCheck( - data.info.applicationInfo); + data.info.applicationInfo, data.compatInfo); IActivityManager mgr = ActivityManagerNative.getDefault(); @@ -1926,7 +1975,7 @@ public final class ActivityThread { unscheduleGcIdler(); // instantiate the BackupAgent class named in the manifest - LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo); + LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo, data.compatInfo); String packageName = packageInfo.mPackageName; if (mBackupAgents.get(packageName) != null) { Slog.d(TAG, "BackupAgent " + " for " + packageName @@ -1988,7 +2037,7 @@ public final class ActivityThread { private final void handleDestroyBackupAgent(CreateBackupAgentData data) { if (DEBUG_BACKUP) Slog.v(TAG, "handleDestroyBackupAgent: " + data); - LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo); + LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo, data.compatInfo); String packageName = packageInfo.mPackageName; BackupAgent agent = mBackupAgents.get(packageName); if (agent != null) { @@ -2010,7 +2059,7 @@ public final class ActivityThread { unscheduleGcIdler(); LoadedApk packageInfo = getPackageInfoNoCheck( - data.info.applicationInfo); + data.info.applicationInfo, data.compatInfo); Service service = null; try { java.lang.ClassLoader cl = packageInfo.getClassLoader(); @@ -2727,6 +2776,18 @@ public final class ActivityThread { } } + private void handleUpdatePackageCompatibilityInfo(UpdateCompatibilityData data) { + LoadedApk apk = peekPackageInfo(data.pkg, false); + if (apk != null) { + apk.mCompatibilityInfo = data.info; + } + apk = peekPackageInfo(data.pkg, true); + if (apk != null) { + apk.mCompatibilityInfo = data.info; + } + handleConfigurationChanged(mConfiguration, data.info); + } + private final void deliverResults(ActivityClientRecord r, List<ResultInfo> results) { final int N = results.size(); for (int i=0; i<N; i++) { @@ -3064,7 +3125,7 @@ public final class ActivityThread { // If there was a pending configuration change, execute it first. if (changedConfig != null) { - handleConfigurationChanged(changedConfig); + handleConfigurationChanged(changedConfig, null); } ActivityClientRecord r = mActivities.get(tmp.token); @@ -3234,11 +3295,12 @@ public final class ActivityThread { } } - final boolean applyConfigurationToResourcesLocked(Configuration config) { + final boolean applyConfigurationToResourcesLocked(Configuration config, + CompatibilityInfo compat) { if (mResConfiguration == null) { mResConfiguration = new Configuration(); } - if (!mResConfiguration.isOtherSeqNewer(config)) { + if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq=" + mResConfiguration.seq + ", newSeq=" + config.seq); return false; @@ -3251,7 +3313,7 @@ public final class ActivityThread { Locale.setDefault(config.locale); } - Resources.updateSystemConfiguration(config, dm); + Resources.updateSystemConfiguration(config, dm, compat); ApplicationPackageManager.configurationChanged(); //Slog.i(TAG, "Configuration changed in " + currentPackageName()); @@ -3266,7 +3328,7 @@ public final class ActivityThread { if (r != null) { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources " + r + " config to: " + config); - r.updateConfiguration(config, dm); + r.updateConfiguration(config, dm, compat); //Slog.i(TAG, "Updated app resources " + v.getKey() // + " " + r + ": " + r.getConfiguration()); } else { @@ -3278,7 +3340,7 @@ public final class ActivityThread { return changes != 0; } - final void handleConfigurationChanged(Configuration config) { + final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) { ArrayList<ComponentCallbacks> callbacks = null; @@ -3297,15 +3359,21 @@ public final class ActivityThread { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: " + config); - applyConfigurationToResourcesLocked(config); + applyConfigurationToResourcesLocked(config, compat); if (mConfiguration == null) { mConfiguration = new Configuration(); } - if (!mConfiguration.isOtherSeqNewer(config)) { + if (!mConfiguration.isOtherSeqNewer(config) && compat == null) { return; } mConfiguration.updateFrom(config); + if (compat != null) { + // Can't do this here, because it causes us to report the + // comatible config back to the am as the current config + // of the activity, and much unhappiness results. + //compat.applyToConfiguration(mConfiguration); + } callbacks = collectComponentCallbacksLocked(false, config); } @@ -3445,9 +3513,10 @@ public final class ActivityThread { * reflect configuration changes. The configuration object passed * in AppBindData can be safely assumed to be up to date */ - Resources.getSystem().updateConfiguration(mConfiguration, null); + Resources.getSystem().updateConfiguration(mConfiguration, + Resources.getSystem().getDisplayMetrics(), data.compatInfo); - data.info = getPackageInfoNoCheck(data.appInfo); + data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); /** * For system applications on userdebug/eng builds, log stack @@ -3539,7 +3608,7 @@ public final class ActivityThread { instrApp.publicSourceDir = ii.publicSourceDir; instrApp.dataDir = ii.dataDir; instrApp.nativeLibraryDir = ii.nativeLibraryDir; - LoadedApk pi = getPackageInfo(instrApp, + LoadedApk pi = getPackageInfo(instrApp, data.compatInfo, appContext.getClassLoader(), false, true); ContextImpl instrContext = new ContextImpl(); instrContext.init(pi, null, this); @@ -3953,7 +4022,7 @@ public final class ActivityThread { // We need to apply this change to the resources // immediately, because upon returning the view // hierarchy will be informed about it. - if (applyConfigurationToResourcesLocked(newConfig)) { + if (applyConfigurationToResourcesLocked(newConfig, null)) { // This actually changed the resources! Tell // everyone about it. if (mPendingConfiguration == null || diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index aa26b04..e1d76a4 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -23,6 +23,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ProviderInfo; import android.content.pm.ServiceInfo; +import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.os.Binder; import android.os.Bundle; @@ -131,12 +132,13 @@ public abstract class ApplicationThreadNative extends Binder IBinder b = data.readStrongBinder(); int ident = data.readInt(); ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data); + CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data); Bundle state = data.readBundle(); List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR); List<Intent> pi = data.createTypedArrayList(Intent.CREATOR); boolean notResumed = data.readInt() != 0; boolean isForward = data.readInt() != 0; - scheduleLaunchActivity(intent, b, ident, info, state, ri, pi, + scheduleLaunchActivity(intent, b, ident, info, compatInfo, state, ri, pi, notResumed, isForward); return true; } @@ -181,11 +183,12 @@ public abstract class ApplicationThreadNative extends Binder data.enforceInterface(IApplicationThread.descriptor); Intent intent = Intent.CREATOR.createFromParcel(data); ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data); + CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data); int resultCode = data.readInt(); String resultData = data.readString(); Bundle resultExtras = data.readBundle(); boolean sync = data.readInt() != 0; - scheduleReceiver(intent, info, resultCode, resultData, + scheduleReceiver(intent, info, compatInfo, resultCode, resultData, resultExtras, sync); return true; } @@ -194,7 +197,8 @@ public abstract class ApplicationThreadNative extends Binder data.enforceInterface(IApplicationThread.descriptor); IBinder token = data.readStrongBinder(); ServiceInfo info = ServiceInfo.CREATOR.createFromParcel(data); - scheduleCreateService(token, info); + CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data); + scheduleCreateService(token, info, compatInfo); return true; } @@ -256,12 +260,13 @@ public abstract class ApplicationThreadNative extends Binder int testMode = data.readInt(); boolean restrictedBackupMode = (data.readInt() != 0); Configuration config = Configuration.CREATOR.createFromParcel(data); + CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data); HashMap<String, IBinder> services = data.readHashMap(null); Bundle coreSettings = data.readBundle(); bindApplication(packageName, info, providers, testName, profileName, testArgs, testWatcher, testMode, restrictedBackupMode, - config, services, coreSettings); + config, compatInfo, services, coreSettings); return true; } @@ -389,8 +394,9 @@ public abstract class ApplicationThreadNative extends Binder { data.enforceInterface(IApplicationThread.descriptor); ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(data); + CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data); int backupMode = data.readInt(); - scheduleCreateBackupAgent(appInfo, backupMode); + scheduleCreateBackupAgent(appInfo, compatInfo, backupMode); return true; } @@ -398,7 +404,8 @@ public abstract class ApplicationThreadNative extends Binder { data.enforceInterface(IApplicationThread.descriptor); ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(data); - scheduleDestroyBackupAgent(appInfo); + CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data); + scheduleDestroyBackupAgent(appInfo, compatInfo); return true; } @@ -456,12 +463,20 @@ public abstract class ApplicationThreadNative extends Binder return true; } - case SET_CORE_SETTINGS: { + case SET_CORE_SETTINGS_TRANSACTION: { data.enforceInterface(IApplicationThread.descriptor); Bundle settings = data.readBundle(); setCoreSettings(settings); return true; } + + case UPDATE_PACKAGE_COMPATIBILITY_INFO_TRANSACTION: { + data.enforceInterface(IApplicationThread.descriptor); + String pkg = data.readString(); + CompatibilityInfo compat = CompatibilityInfo.CREATOR.createFromParcel(data); + updatePackageCompatibilityInfo(pkg, compat); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -554,7 +569,8 @@ class ApplicationThreadProxy implements IApplicationThread { } public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, - ActivityInfo info, Bundle state, List<ResultInfo> pendingResults, + ActivityInfo info, CompatibilityInfo compatInfo, Bundle state, + List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) throws RemoteException { Parcel data = Parcel.obtain(); @@ -563,6 +579,7 @@ class ApplicationThreadProxy implements IApplicationThread { data.writeStrongBinder(token); data.writeInt(ident); info.writeToParcel(data, 0); + compatInfo.writeToParcel(data, 0); data.writeBundle(state); data.writeTypedList(pendingResults); data.writeTypedList(pendingNewIntents); @@ -619,12 +636,13 @@ class ApplicationThreadProxy implements IApplicationThread { } public final void scheduleReceiver(Intent intent, ActivityInfo info, - int resultCode, String resultData, + CompatibilityInfo compatInfo, int resultCode, String resultData, Bundle map, boolean sync) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); intent.writeToParcel(data, 0); info.writeToParcel(data, 0); + compatInfo.writeToParcel(data, 0); data.writeInt(resultCode); data.writeString(resultData); data.writeBundle(map); @@ -634,32 +652,36 @@ class ApplicationThreadProxy implements IApplicationThread { data.recycle(); } - public final void scheduleCreateBackupAgent(ApplicationInfo app, int backupMode) - throws RemoteException { + public final void scheduleCreateBackupAgent(ApplicationInfo app, + CompatibilityInfo compatInfo, int backupMode) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); app.writeToParcel(data, 0); + compatInfo.writeToParcel(data, 0); data.writeInt(backupMode); mRemote.transact(SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } - public final void scheduleDestroyBackupAgent(ApplicationInfo app) throws RemoteException { + public final void scheduleDestroyBackupAgent(ApplicationInfo app, + CompatibilityInfo compatInfo) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); app.writeToParcel(data, 0); + compatInfo.writeToParcel(data, 0); mRemote.transact(SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } - public final void scheduleCreateService(IBinder token, ServiceInfo info) - throws RemoteException { + public final void scheduleCreateService(IBinder token, ServiceInfo info, + CompatibilityInfo compatInfo) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeStrongBinder(token); info.writeToParcel(data, 0); + compatInfo.writeToParcel(data, 0); mRemote.transact(SCHEDULE_CREATE_SERVICE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); @@ -719,7 +741,7 @@ class ApplicationThreadProxy implements IApplicationThread { public final void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers, ComponentName testName, String profileName, Bundle testArgs, IInstrumentationWatcher testWatcher, int debugMode, - boolean restrictedBackupMode, Configuration config, + boolean restrictedBackupMode, Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); @@ -738,6 +760,7 @@ class ApplicationThreadProxy implements IApplicationThread { data.writeInt(debugMode); data.writeInt(restrictedBackupMode ? 1 : 0); config.writeToParcel(data, 0); + compatInfo.writeToParcel(data, 0); data.writeMap(services); data.writeBundle(coreSettings); mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null, @@ -952,6 +975,16 @@ class ApplicationThreadProxy implements IApplicationThread { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeBundle(coreSettings); - mRemote.transact(SET_CORE_SETTINGS, data, null, IBinder.FLAG_ONEWAY); + mRemote.transact(SET_CORE_SETTINGS_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); + } + + public void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) + throws RemoteException { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(IApplicationThread.descriptor); + data.writeString(pkg); + info.writeToParcel(data, 0); + mRemote.transact(UPDATE_PACKAGE_COMPATIBILITY_INFO_TRANSACTION, data, null, + IBinder.FLAG_ONEWAY); } } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index cc1f81c..36b9d72 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1372,7 +1372,7 @@ class ContextImpl extends Context { } LoadedApk pi = - mMainThread.getPackageInfo(packageName, flags); + mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), flags); if (pi != null) { ContextImpl c = new ContextImpl(); c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED; @@ -1454,7 +1454,7 @@ class ContextImpl extends Context { " compatiblity info:" + container.getDisplayMetrics()); } mResources = mainThread.getTopLevelResources( - mPackageInfo.getResDir(), container.getCompatibilityInfo().copy()); + mPackageInfo.getResDir(), container.getCompatibilityInfo()); } mMainThread = mainThread; mContentResolver = new ApplicationContentResolver(this, mainThread); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 61e6fc8..4c2ccf4 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -342,6 +342,9 @@ public interface IActivityManager extends IInterface { public int startActivitiesInPackage(int uid, Intent[] intents, String[] resolvedTypes, IBinder resultTo) throws RemoteException; + public void setPackageScreenCompatMode(String packageName, boolean compatEnabled) + throws RemoteException; + /* * Private non-Binder interfaces */ @@ -557,4 +560,5 @@ public interface IActivityManager extends IInterface { int START_ACTIVITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+120; int START_ACTIVITIES_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+121; int ACTIVITY_SLEPT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+122; + int SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+123; } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index 55177a9..93a8ff3 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -23,6 +23,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ProviderInfo; import android.content.pm.ServiceInfo; +import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.os.Bundle; import android.os.Debug; @@ -52,7 +53,8 @@ public interface IApplicationThread extends IInterface { void scheduleResumeActivity(IBinder token, boolean isForward) throws RemoteException; void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException; void scheduleLaunchActivity(Intent intent, IBinder token, int ident, - ActivityInfo info, Bundle state, List<ResultInfo> pendingResults, + ActivityInfo info, CompatibilityInfo compatInfo, Bundle state, + List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) throws RemoteException; void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults, @@ -61,14 +63,17 @@ public interface IApplicationThread extends IInterface { void scheduleNewIntent(List<Intent> intent, IBinder token) throws RemoteException; void scheduleDestroyActivity(IBinder token, boolean finished, int configChanges) throws RemoteException; - void scheduleReceiver(Intent intent, ActivityInfo info, int resultCode, - String data, Bundle extras, boolean sync) throws RemoteException; + void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo, + int resultCode, String data, Bundle extras, boolean sync) throws RemoteException; static final int BACKUP_MODE_INCREMENTAL = 0; static final int BACKUP_MODE_FULL = 1; static final int BACKUP_MODE_RESTORE = 2; - void scheduleCreateBackupAgent(ApplicationInfo app, int backupMode) throws RemoteException; - void scheduleDestroyBackupAgent(ApplicationInfo app) throws RemoteException; - void scheduleCreateService(IBinder token, ServiceInfo info) throws RemoteException; + void scheduleCreateBackupAgent(ApplicationInfo app, CompatibilityInfo compatInfo, + int backupMode) throws RemoteException; + void scheduleDestroyBackupAgent(ApplicationInfo app, CompatibilityInfo compatInfo) + throws RemoteException; + void scheduleCreateService(IBinder token, ServiceInfo info, + CompatibilityInfo compatInfo) throws RemoteException; void scheduleBindService(IBinder token, Intent intent, boolean rebind) throws RemoteException; void scheduleUnbindService(IBinder token, @@ -82,7 +87,7 @@ public interface IApplicationThread extends IInterface { void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers, ComponentName testName, String profileName, Bundle testArguments, IInstrumentationWatcher testWatcher, int debugMode, boolean restrictedBackupMode, - Configuration config, Map<String, IBinder> services, + Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) throws RemoteException; void scheduleExit() throws RemoteException; void scheduleSuicide() throws RemoteException; @@ -112,6 +117,7 @@ public interface IApplicationThread extends IInterface { void dumpActivity(FileDescriptor fd, IBinder servicetoken, String prefix, String[] args) throws RemoteException; void setCoreSettings(Bundle coreSettings) throws RemoteException; + void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException; String descriptor = "android.app.IApplicationThread"; @@ -153,5 +159,6 @@ public interface IApplicationThread extends IInterface { int DUMP_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+36; int CLEAR_DNS_CACHE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+37; int SET_HTTP_PROXY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+38; - int SET_CORE_SETTINGS = IBinder.FIRST_CALL_TRANSACTION+39; + int SET_CORE_SETTINGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+39; + int UPDATE_PACKAGE_COMPATIBILITY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+40; } diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index c406524..5307696 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -99,6 +99,7 @@ final class LoadedApk { } public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo, + CompatibilityInfo compatInfo, ActivityThread mainThread, ClassLoader baseLoader, boolean securityViolation, boolean includeCode) { mActivityThread = activityThread; @@ -114,7 +115,7 @@ final class LoadedApk { mBaseClassLoader = baseLoader; mSecurityViolation = securityViolation; mIncludeCode = includeCode; - mCompatibilityInfo = new CompatibilityInfo(aInfo); + mCompatibilityInfo = compatInfo; if (mAppDir == null) { if (ActivityThread.mSystemContext == null) { @@ -122,7 +123,8 @@ final class LoadedApk { ContextImpl.createSystemContext(mainThread); ActivityThread.mSystemContext.getResources().updateConfiguration( mainThread.getConfiguration(), - mainThread.getDisplayMetricsLocked(false)); + mainThread.getDisplayMetricsLocked(false), + compatInfo); //Slog.i(TAG, "Created system resources " // + mSystemContext.getResources() + ": " // + mSystemContext.getResources().getConfiguration()); @@ -133,7 +135,7 @@ final class LoadedApk { } public LoadedApk(ActivityThread activityThread, String name, - Context systemContext, ApplicationInfo info) { + Context systemContext, ApplicationInfo info, CompatibilityInfo compatInfo) { mActivityThread = activityThread; mApplicationInfo = info != null ? info : new ApplicationInfo(); mApplicationInfo.packageName = name; @@ -149,7 +151,7 @@ final class LoadedApk { mIncludeCode = true; mClassLoader = systemContext.getClassLoader(); mResources = systemContext.getResources(); - mCompatibilityInfo = new CompatibilityInfo(mApplicationInfo); + mCompatibilityInfo = compatInfo; } public String getPackageName() { diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index e403ac2..ab9bfce 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -21,9 +21,9 @@ import android.graphics.Canvas; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; +import android.os.Parcel; +import android.os.Parcelable; import android.util.DisplayMetrics; -import android.util.Log; -import android.view.Gravity; import android.view.MotionEvent; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; @@ -34,32 +34,27 @@ import android.view.WindowManager.LayoutParams; * * {@hide} */ -public class CompatibilityInfo { - private static final boolean DBG = false; - private static final String TAG = "CompatibilityInfo"; - +public class CompatibilityInfo implements Parcelable { /** default compatibility info object for compatible applications */ public static final CompatibilityInfo DEFAULT_COMPATIBILITY_INFO = new CompatibilityInfo() { - @Override - public void setExpandable(boolean expandable) { - throw new UnsupportedOperationException("trying to change default compatibility info"); - } }; /** - * The default width of the screen in portrait mode. + * This is the number of pixels we would like to have along the + * short axis of an app that needs to run on a normal size screen. */ - public static final int DEFAULT_PORTRAIT_WIDTH = 320; + public static final int DEFAULT_NORMAL_SHORT_DIMENSION = 320; /** - * The default height of the screen in portrait mode. - */ - public static final int DEFAULT_PORTRAIT_HEIGHT = 480; + * This is the maximum aspect ratio we will allow while keeping + * applications in a compatible screen size. + */ + public static final float MAXIMUM_ASPECT_RATIO = (854f/480f); /** * A compatibility flags */ - private int mCompatibilityFlags; + private final int mCompatibilityFlags; /** * A flag mask to tell if the application needs scaling (when mApplicationScale != 1.0f) @@ -68,54 +63,27 @@ public class CompatibilityInfo { private static final int SCALING_REQUIRED = 1; /** - * A flag mask 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 <supports-screens> or - * 2) Configuration.SCREENLAYOUT_COMPAT_NEEDED is not set - * {@see compatibilityFlag} + * Has the application said that its UI is expandable? Based on the + * <supports-screen> android:expandible in the manifest. */ private static final int EXPANDABLE = 2; /** - * A flag mask to tell if the application is configured to be expandable. This differs - * from EXPANDABLE in that the application that is not expandable will be - * marked as expandable if Configuration.SCREENLAYOUT_COMPAT_NEEDED is not set. - */ - private static final int CONFIGURED_EXPANDABLE = 4; - - /** - * A flag mask to indicates that the application supports large screens. - * The flag is set to true if - * 1) Application declares it supports large screens in manifest file using <supports-screens> or - * 2) The screen size is not large - * {@see compatibilityFlag} + * Has the application said that its UI supports large screens? Based on the + * <supports-screen> android:largeScreens in the manifest. */ private static final int LARGE_SCREENS = 8; /** - * A flag mask to tell if the application supports large screens. This differs - * from LARGE_SCREENS in that the application that does not support large - * screens will be marked as supporting them if the current screen is not - * large. - */ - private static final int CONFIGURED_LARGE_SCREENS = 16; - - /** - * A flag mask to indicates that the application supports xlarge screens. - * The flag is set to true if - * 1) Application declares it supports xlarge screens in manifest file using <supports-screens> or - * 2) The screen size is not xlarge - * {@see compatibilityFlag} + * Has the application said that its UI supports xlarge screens? Based on the + * <supports-screen> android:xlargeScreens in the manifest. */ private static final int XLARGE_SCREENS = 32; /** - * A flag mask to tell if the application supports xlarge screens. This differs - * from XLARGE_SCREENS in that the application that does not support xlarge - * screens will be marked as supporting them if the current screen is not - * xlarge. + * Set if the application needs to run in screen size compatibility mode. */ - private static final int CONFIGURED_XLARGE_SCREENS = 64; + private static final int NEEDS_SCREEN_COMPAT = 128; /** * The effective screen density we have selected for this application. @@ -132,28 +100,55 @@ public class CompatibilityInfo { */ public final float applicationInvertedScale; - /** - * The flags from ApplicationInfo. - */ - public final int appFlags; - - public CompatibilityInfo(ApplicationInfo appInfo) { - appFlags = appInfo.flags; - + public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, boolean forceCompat) { + int compatFlags = 0; + if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { - // Saying you support large screens also implies you support xlarge - // screens; there is no compatibility mode for a large app on an - // xlarge screen. - mCompatibilityFlags |= LARGE_SCREENS | CONFIGURED_LARGE_SCREENS - | XLARGE_SCREENS | CONFIGURED_XLARGE_SCREENS - | EXPANDABLE | CONFIGURED_EXPANDABLE; + compatFlags |= LARGE_SCREENS; + if (!forceCompat) { + // If we aren't forcing the app into compatibility mode, then + // assume if it supports large screens that we should allow it + // to use the full space of an xlarge screen as well. + compatFlags |= XLARGE_SCREENS | EXPANDABLE; + } } if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { - mCompatibilityFlags |= XLARGE_SCREENS | CONFIGURED_XLARGE_SCREENS - | EXPANDABLE | CONFIGURED_EXPANDABLE; + compatFlags |= XLARGE_SCREENS | EXPANDABLE; + } + if (!forceCompat) { + // If we are forcing compatibility mode, then ignore an app that + // just says it is resizable for screens. We'll only have it fill + // the screen if it explicitly says it supports the screen size we + // are running in. + if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { + compatFlags |= EXPANDABLE; + } + } + + boolean supportsScreen = false; + switch (screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) { + case Configuration.SCREENLAYOUT_SIZE_XLARGE: + if ((compatFlags&XLARGE_SCREENS) != 0) { + supportsScreen = true; + } + break; + case Configuration.SCREENLAYOUT_SIZE_LARGE: + if ((compatFlags&LARGE_SCREENS) != 0) { + supportsScreen = true; + } + break; + } + + if ((screenLayout&Configuration.SCREENLAYOUT_COMPAT_NEEDED) == 0) { + if ((compatFlags&EXPANDABLE) != 0) { + supportsScreen = true; + } } - if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { - mCompatibilityFlags |= EXPANDABLE | CONFIGURED_EXPANDABLE; + + if (supportsScreen) { + compatFlags &= ~NEEDS_SCREEN_COMPAT; + } else { + compatFlags |= NEEDS_SCREEN_COMPAT; } if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { @@ -165,13 +160,14 @@ public class CompatibilityInfo { applicationScale = DisplayMetrics.DENSITY_DEVICE / (float) DisplayMetrics.DENSITY_DEFAULT; applicationInvertedScale = 1.0f / applicationScale; - mCompatibilityFlags |= SCALING_REQUIRED; + compatFlags |= SCALING_REQUIRED; } + + mCompatibilityFlags = compatFlags; } - private CompatibilityInfo(int appFlags, int compFlags, + private CompatibilityInfo(int compFlags, int dens, float scale, float invertedScale) { - this.appFlags = appFlags; mCompatibilityFlags = compFlags; applicationDensity = dens; applicationScale = scale; @@ -179,81 +175,13 @@ public class CompatibilityInfo { } private CompatibilityInfo() { - this(ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS - | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS - | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS - | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS - | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS, - EXPANDABLE | CONFIGURED_EXPANDABLE, + this(XLARGE_SCREENS | LARGE_SCREENS | EXPANDABLE, DisplayMetrics.DENSITY_DEVICE, 1.0f, 1.0f); } /** - * Returns the copy of this instance. - */ - public CompatibilityInfo copy() { - CompatibilityInfo info = new CompatibilityInfo(appFlags, mCompatibilityFlags, - applicationDensity, applicationScale, applicationInvertedScale); - return info; - } - - /** - * Sets expandable bit in the compatibility flag. - */ - public void setExpandable(boolean expandable) { - if (expandable) { - mCompatibilityFlags |= CompatibilityInfo.EXPANDABLE; - } else { - mCompatibilityFlags &= ~CompatibilityInfo.EXPANDABLE; - } - } - - /** - * Sets large screen bit in the compatibility flag. - */ - public void setLargeScreens(boolean expandable) { - if (expandable) { - mCompatibilityFlags |= CompatibilityInfo.LARGE_SCREENS; - } else { - mCompatibilityFlags &= ~CompatibilityInfo.LARGE_SCREENS; - } - } - - /** - * Sets large screen bit in the compatibility flag. - */ - public void setXLargeScreens(boolean expandable) { - if (expandable) { - mCompatibilityFlags |= CompatibilityInfo.XLARGE_SCREENS; - } else { - mCompatibilityFlags &= ~CompatibilityInfo.XLARGE_SCREENS; - } - } - - /** - * @return true if the application is configured to be expandable. - */ - public boolean isConfiguredExpandable() { - return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_EXPANDABLE) != 0; - } - - /** - * @return true if the application is configured to be expandable. - */ - public boolean isConfiguredLargeScreens() { - return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_LARGE_SCREENS) != 0; - } - - /** - * @return true if the application is configured to be expandable. - */ - public boolean isConfiguredXLargeScreens() { - return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_XLARGE_SCREENS) != 0; - } - - /** * @return true if the scaling is required */ public boolean isScalingRequired() { @@ -261,14 +189,12 @@ public class CompatibilityInfo { } public boolean supportsScreen() { - return (mCompatibilityFlags & (EXPANDABLE|LARGE_SCREENS)) - == (EXPANDABLE|LARGE_SCREENS); + return (mCompatibilityFlags&NEEDS_SCREEN_COMPAT) == 0; } @Override public String toString() { - return "CompatibilityInfo{scale=" + applicationScale + - ", supports screen=" + supportsScreen() + "}"; + return "CompatibilityInfo{scale=" + applicationScale + "}"; } /** @@ -423,24 +349,144 @@ public class CompatibilityInfo { } } + public void applyToDisplayMetrics(DisplayMetrics inoutDm) { + if (!supportsScreen()) { + // This is a larger screen device and the app is not + // compatible with large screens, so diddle it. + CompatibilityInfo.updateCompatibleScreenFrame(inoutDm, null, inoutDm); + } + + if (isScalingRequired()) { + float invertedRatio = applicationInvertedScale; + inoutDm.density *= invertedRatio; + inoutDm.densityDpi = (int)((inoutDm.density*DisplayMetrics.DENSITY_DEFAULT)+.5f); + inoutDm.scaledDensity *= invertedRatio; + inoutDm.xdpi *= invertedRatio; + inoutDm.ydpi *= invertedRatio; + inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertedRatio + 0.5f); + inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertedRatio + 0.5f); + } + } + + public void applyToConfiguration(Configuration inoutConfig) { + if (!supportsScreen()) { + // This is a larger screen device and the app is not + // compatible with large screens, so we are forcing it to + // run as if the screen is normal size. + inoutConfig.screenLayout = + (inoutConfig.screenLayout&~Configuration.SCREENLAYOUT_SIZE_MASK) + | Configuration.SCREENLAYOUT_SIZE_NORMAL; + } + } + /** - * Returns the frame Rect for applications runs under compatibility mode. + * Compute the frame Rect for applications runs under compatibility mode. * * @param dm the display metrics used to compute the frame size. * @param orientation the orientation of the screen. * @param outRect the output parameter which will contain the result. + * @return Returns the scaling factor for the window. */ - public static void updateCompatibleScreenFrame(DisplayMetrics dm, int orientation, - Rect outRect) { - int width = dm.widthPixels; - int portraitHeight = (int) (DEFAULT_PORTRAIT_HEIGHT * dm.density + 0.5f); - int portraitWidth = (int) (DEFAULT_PORTRAIT_WIDTH * dm.density + 0.5f); - if (orientation == Configuration.ORIENTATION_LANDSCAPE) { - int xOffset = (width - portraitHeight) / 2 ; - outRect.set(xOffset, 0, xOffset + portraitHeight, portraitWidth); + public static float updateCompatibleScreenFrame(DisplayMetrics dm, + Rect outRect, DisplayMetrics outDm) { + final int width = dm.realWidthPixels; + final int height = dm.realHeightPixels; + int shortSize, longSize; + if (width < height) { + shortSize = width; + longSize = height; + } else { + shortSize = height; + longSize = width; + } + int newShortSize = (int)(DEFAULT_NORMAL_SHORT_DIMENSION * dm.density + 0.5f); + float aspect = ((float)longSize) / shortSize; + if (aspect > MAXIMUM_ASPECT_RATIO) { + aspect = MAXIMUM_ASPECT_RATIO; + } + int newLongSize = (int)(newShortSize * aspect + 0.5f); + int newWidth, newHeight; + if (width < height) { + newWidth = newShortSize; + newHeight = newLongSize; } else { - int xOffset = (width - portraitWidth) / 2 ; - outRect.set(xOffset, 0, xOffset + portraitWidth, portraitHeight); + newWidth = newLongSize; + newHeight = newShortSize; + } + + float sw = width/(float)newWidth; + float sh = height/(float)newHeight; + float scale = sw < sh ? sw : sh; + if (scale < 1) { + scale = 1; } + + if (outRect != null) { + final int left = (int)((width-(newWidth*scale))/2); + final int top = (int)((height-(newHeight*scale))/2); + outRect.set(left, top, left+newWidth, top+newHeight); + } + + if (outDm != null) { + outDm.widthPixels = newWidth; + outDm.heightPixels = newHeight; + } + + return scale; + } + + @Override + public boolean equals(Object o) { + try { + CompatibilityInfo oc = (CompatibilityInfo)o; + if (mCompatibilityFlags != oc.mCompatibilityFlags) return false; + if (applicationDensity != oc.applicationDensity) return false; + if (applicationScale != oc.applicationScale) return false; + if (applicationInvertedScale != oc.applicationInvertedScale) return false; + return true; + } catch (ClassCastException e) { + return false; + } + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + mCompatibilityFlags; + result = 31 * result + applicationDensity; + result = 31 * result + Float.floatToIntBits(applicationScale); + result = 31 * result + Float.floatToIntBits(applicationInvertedScale); + return result; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mCompatibilityFlags); + dest.writeInt(applicationDensity); + dest.writeFloat(applicationScale); + dest.writeFloat(applicationInvertedScale); + } + + public static final Parcelable.Creator<CompatibilityInfo> CREATOR + = new Parcelable.Creator<CompatibilityInfo>() { + public CompatibilityInfo createFromParcel(Parcel source) { + return new CompatibilityInfo(source); + } + + public CompatibilityInfo[] newArray(int size) { + return new CompatibilityInfo[size]; + } + }; + + private CompatibilityInfo(Parcel source) { + mCompatibilityFlags = source.readInt(); + applicationDensity = source.readInt(); + applicationScale = source.readFloat(); + applicationInvertedScale = source.readFloat(); } } diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 47c2623..908db11 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -703,11 +703,20 @@ public final class Configuration implements Parcelable, Comparable<Configuration } public int hashCode() { - return ((int)this.fontScale) + this.mcc + this.mnc - + (this.locale != null ? this.locale.hashCode() : 0) - + this.touchscreen - + this.keyboard + this.keyboardHidden + this.hardKeyboardHidden - + this.navigation + this.navigationHidden - + this.orientation + this.screenLayout + this.uiMode; + int result = 17; + result = 31 * result + Float.floatToIntBits(fontScale); + result = 31 * result + mcc; + result = 31 * result + mnc; + result = 31 * result + (locale != null ? locale.hashCode() : 0); + result = 31 * result + touchscreen; + result = 31 * result + keyboard; + result = 31 * result + keyboardHidden; + result = 31 * result + hardKeyboardHidden; + result = 31 * result + navigation; + result = 31 * result + navigationHidden; + result = 31 * result + orientation; + result = 31 * result + screenLayout; + result = 31 * result + uiMode; + return result; } } diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 81eb09c..00b49e8 100755 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -91,6 +91,7 @@ public class Resources { private static boolean mPreloaded; /*package*/ final TypedValue mTmpValue = new TypedValue(); + /*package*/ final Configuration mTmpConfig = new Configuration(); // These are protected by the mTmpValue lock. private final LongSparseArray<WeakReference<Drawable.ConstantState> > mDrawableCache @@ -1400,18 +1401,30 @@ public class Resources { */ public void updateConfiguration(Configuration config, DisplayMetrics metrics) { + updateConfiguration(config, metrics, null); + } + + /** + * @hide + */ + public void updateConfiguration(Configuration config, + DisplayMetrics metrics, CompatibilityInfo compat) { synchronized (mTmpValue) { + if (compat != null) { + mCompatibilityInfo = compat; + } int configChanges = 0xfffffff; if (config != null) { - configChanges = mConfiguration.updateFrom(config); + mTmpConfig.setTo(config); + mCompatibilityInfo.applyToConfiguration(mTmpConfig); + configChanges = mConfiguration.updateFrom(mTmpConfig); } if (mConfiguration.locale == null) { mConfiguration.locale = Locale.getDefault(); } if (metrics != null) { mMetrics.setTo(metrics); - mMetrics.updateMetrics(mCompatibilityInfo, - mConfiguration.orientation, mConfiguration.screenLayout); + mCompatibilityInfo.applyToDisplayMetrics(mMetrics); } mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale; @@ -1500,15 +1513,23 @@ public class Resources { * * @hide */ - public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics) { + public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics, + CompatibilityInfo compat) { if (mSystem != null) { - mSystem.updateConfiguration(config, metrics); + mSystem.updateConfiguration(config, metrics, compat); //Log.i(TAG, "Updated system resources " + mSystem // + ": " + mSystem.getConfiguration()); } } /** + * @hide + */ + public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics) { + updateSystemConfiguration(config, metrics, null); + } + + /** * Return the current display metrics that are in effect for this resource * object. The returned object should be treated as read-only. * diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index 63baf14..8018ff9 100644 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -16,9 +16,7 @@ package android.util; -import android.content.res.CompatibilityInfo; -import android.content.res.Configuration; -import android.os.*; +import android.os.SystemProperties; /** @@ -107,6 +105,11 @@ public class DisplayMetrics { */ public float ydpi; + /** @hide */ + public int realWidthPixels; + /** @hide */ + public int realHeightPixels; + public DisplayMetrics() { } @@ -118,6 +121,8 @@ public class DisplayMetrics { scaledDensity = o.scaledDensity; xdpi = o.xdpi; ydpi = o.ydpi; + realWidthPixels = o.realWidthPixels; + realHeightPixels = o.realHeightPixels; } public void setToDefaults() { @@ -128,101 +133,8 @@ public class DisplayMetrics { scaledDensity = density; xdpi = DENSITY_DEVICE; ydpi = DENSITY_DEVICE; - } - - /** - * Update the display metrics based on the compatibility info and orientation - * NOTE: DO NOT EXPOSE THIS API! It is introducing a circular dependency - * with the higher-level android.res package. - * {@hide} - */ - public void updateMetrics(CompatibilityInfo compatibilityInfo, int orientation, - int screenLayout) { - boolean expandable = compatibilityInfo.isConfiguredExpandable(); - boolean largeScreens = compatibilityInfo.isConfiguredLargeScreens(); - boolean xlargeScreens = compatibilityInfo.isConfiguredXLargeScreens(); - - // Note: this assume that configuration is updated before calling - // updateMetrics method. - if (!expandable) { - if ((screenLayout&Configuration.SCREENLAYOUT_COMPAT_NEEDED) == 0) { - expandable = true; - // the current screen size is compatible with non-resizing apps. - compatibilityInfo.setExpandable(true); - } else { - compatibilityInfo.setExpandable(false); - } - } - if (!largeScreens) { - if ((screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) - != Configuration.SCREENLAYOUT_SIZE_LARGE) { - largeScreens = true; - // the current screen size is not large. - compatibilityInfo.setLargeScreens(true); - } else { - compatibilityInfo.setLargeScreens(false); - } - } - if (!xlargeScreens) { - if ((screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) - != Configuration.SCREENLAYOUT_SIZE_XLARGE) { - xlargeScreens = true; - // the current screen size is not large. - compatibilityInfo.setXLargeScreens(true); - } else { - compatibilityInfo.setXLargeScreens(false); - } - } - - if (!expandable || (!largeScreens && !xlargeScreens)) { - // This is a larger screen device and the app is not - // compatible with large screens, so diddle it. - - // Figure out the compatibility width and height of the screen. - int defaultWidth; - int defaultHeight; - switch (orientation) { - case Configuration.ORIENTATION_LANDSCAPE: { - defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density + - 0.5f); - defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density + - 0.5f); - break; - } - case Configuration.ORIENTATION_PORTRAIT: - case Configuration.ORIENTATION_SQUARE: - default: { - defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density + - 0.5f); - defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density + - 0.5f); - break; - } - case Configuration.ORIENTATION_UNDEFINED: { - // don't change - return; - } - } - - if (defaultWidth < widthPixels) { - // content/window's x offset in original pixels - widthPixels = defaultWidth; - } - if (defaultHeight < heightPixels) { - heightPixels = defaultHeight; - } - } - - if (compatibilityInfo.isScalingRequired()) { - float invertedRatio = compatibilityInfo.applicationInvertedScale; - density *= invertedRatio; - densityDpi = (int)((density*DisplayMetrics.DENSITY_DEFAULT)+.5f); - scaledDensity *= invertedRatio; - xdpi *= invertedRatio; - ydpi *= invertedRatio; - widthPixels = (int) (widthPixels * invertedRatio + 0.5f); - heightPixels = (int) (heightPixels * invertedRatio + 0.5f); - } + realWidthPixels = 0; + realHeightPixels = 0; } @Override diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 126f409..89767f2 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -139,6 +139,9 @@ public class Display outMetrics.scaledDensity= outMetrics.density; outMetrics.xdpi = mDpiX; outMetrics.ydpi = mDpiY; + + outMetrics.realWidthPixels = outMetrics.widthPixels; + outMetrics.realHeightPixels = outMetrics.heightPixels; } /* diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 334c68e..2058991 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -458,6 +458,18 @@ public interface WindowManagerPolicy { public int getMaxWallpaperLayer(); /** + * Return the display width available after excluding the window + * decor. + */ + public int getNonDecorDisplayWidth(int fullWidth); + + /** + * Return the display height available after excluding the screen + * decor. + */ + public int getNonDecorDisplayHeight(int fullHeight); + + /** * Return whether the given window should forcibly hide everything * behind it. Typically returns true for the keyguard. */ |