diff options
| author | Dianne Hackborn <hackbod@google.com> | 2011-05-27 16:45:31 -0700 |
|---|---|---|
| committer | Dianne Hackborn <hackbod@google.com> | 2011-05-27 16:49:29 -0700 |
| commit | 8ea5e1d79eb1f05ee7628b0d45ea8fc8eea5330d (patch) | |
| tree | a676c6b0daf45a90b600d3268bb37e81f23a2275 | |
| parent | b96cbbd11c4590bec846212c33361e02293f18b5 (diff) | |
| download | frameworks_base-8ea5e1d79eb1f05ee7628b0d45ea8fc8eea5330d.zip frameworks_base-8ea5e1d79eb1f05ee7628b0d45ea8fc8eea5330d.tar.gz frameworks_base-8ea5e1d79eb1f05ee7628b0d45ea8fc8eea5330d.tar.bz2 | |
Fix compat mode bugs when updating apps.
No longer accidentally puts an app into compatibility mode.
Also various cleanup, freezing screen while switching between modes.
Change-Id: Ic1b3958be7800189a93f68e9dee3c5adfc45fe57
6 files changed, 141 insertions, 85 deletions
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index c151e32..e42caca 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -63,37 +63,19 @@ public class CompatibilityInfo implements Parcelable { private static final int SCALING_REQUIRED = 1; /** - * 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; - - /** - * 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; - - /** - * 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; - - /** * Application must always run in compatibility mode? */ - private static final int ALWAYS_COMPAT = 64; + private static final int ALWAYS_NEEDS_COMPAT = 2; /** * Application never should run in compatibility mode? */ - private static final int NEVER_COMPAT = 128; + private static final int NEVER_NEEDS_COMPAT = 4; /** * Set if the application needs to run in screen size compatibility mode. */ - private static final int NEEDS_SCREEN_COMPAT = 256; + private static final int NEEDS_SCREEN_COMPAT = 8; /** * The effective screen density we have selected for this application. @@ -127,7 +109,7 @@ public class CompatibilityInfo implements Parcelable { } if (compat >= sw) { - compatFlags |= NEVER_COMPAT; + compatFlags |= NEVER_NEEDS_COMPAT; } else if (forceCompat) { compatFlags |= NEEDS_SCREEN_COMPAT; } @@ -138,29 +120,49 @@ public class CompatibilityInfo implements Parcelable { applicationInvertedScale = 1.0f; } else { + /** + * Has the application said that its UI is expandable? Based on the + * <supports-screen> android:expandible in the manifest. + */ + final int EXPANDABLE = 2; + + /** + * Has the application said that its UI supports large screens? Based on the + * <supports-screen> android:largeScreens in the manifest. + */ + final int LARGE_SCREENS = 8; + + /** + * Has the application said that its UI supports xlarge screens? Based on the + * <supports-screen> android:xlargeScreens in the manifest. + */ + final int XLARGE_SCREENS = 32; + + int sizeInfo = 0; + // We can't rely on the application always setting // FLAG_RESIZEABLE_FOR_SCREENS so will compute it based on various input. boolean anyResizeable = false; if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { - compatFlags |= LARGE_SCREENS; + sizeInfo |= LARGE_SCREENS; anyResizeable = true; 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; + sizeInfo |= XLARGE_SCREENS | EXPANDABLE; } } if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { anyResizeable = true; if (!forceCompat) { - compatFlags |= XLARGE_SCREENS | EXPANDABLE; + sizeInfo |= XLARGE_SCREENS | EXPANDABLE; } } if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { anyResizeable = true; - compatFlags |= EXPANDABLE; + sizeInfo |= EXPANDABLE; } if (forceCompat) { @@ -168,43 +170,37 @@ public class CompatibilityInfo implements Parcelable { // 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. - compatFlags &= ~EXPANDABLE; + sizeInfo &= ~EXPANDABLE; } - boolean supportsScreen = false; + compatFlags |= NEEDS_SCREEN_COMPAT; switch (screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) { case Configuration.SCREENLAYOUT_SIZE_XLARGE: - if ((compatFlags&XLARGE_SCREENS) != 0) { - supportsScreen = true; + if ((sizeInfo&XLARGE_SCREENS) != 0) { + compatFlags &= ~NEEDS_SCREEN_COMPAT; } if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { - compatFlags |= NEVER_COMPAT; + compatFlags |= NEVER_NEEDS_COMPAT; } break; case Configuration.SCREENLAYOUT_SIZE_LARGE: - if ((compatFlags&LARGE_SCREENS) != 0) { - supportsScreen = true; + if ((sizeInfo&LARGE_SCREENS) != 0) { + compatFlags &= ~NEEDS_SCREEN_COMPAT; } if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { - compatFlags |= NEVER_COMPAT; + compatFlags |= NEVER_NEEDS_COMPAT; } break; } if ((screenLayout&Configuration.SCREENLAYOUT_COMPAT_NEEDED) != 0) { - if ((compatFlags&EXPANDABLE) != 0) { - supportsScreen = true; + if ((sizeInfo&EXPANDABLE) != 0) { + compatFlags &= ~NEEDS_SCREEN_COMPAT; } else if (!anyResizeable) { - compatFlags |= ALWAYS_COMPAT; + compatFlags |= ALWAYS_NEEDS_COMPAT; } } - if (supportsScreen) { - compatFlags &= ~NEEDS_SCREEN_COMPAT; - } else { - compatFlags |= NEEDS_SCREEN_COMPAT; - } - if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { applicationDensity = DisplayMetrics.DENSITY_DEVICE; applicationScale = 1.0f; @@ -230,8 +226,7 @@ public class CompatibilityInfo implements Parcelable { } private CompatibilityInfo() { - this(XLARGE_SCREENS | LARGE_SCREENS | EXPANDABLE, - DisplayMetrics.DENSITY_DEVICE, + this(NEVER_NEEDS_COMPAT, DisplayMetrics.DENSITY_DEVICE, 1.0f, 1.0f); } @@ -240,7 +235,7 @@ public class CompatibilityInfo implements Parcelable { * @return true if the scaling is required */ public boolean isScalingRequired() { - return (mCompatibilityFlags & SCALING_REQUIRED) != 0; + return (mCompatibilityFlags&SCALING_REQUIRED) != 0; } public boolean supportsScreen() { @@ -248,16 +243,11 @@ public class CompatibilityInfo implements Parcelable { } public boolean neverSupportsScreen() { - return (mCompatibilityFlags&NEVER_COMPAT) != 0; + return (mCompatibilityFlags&NEVER_NEEDS_COMPAT) != 0; } public boolean alwaysSupportsScreen() { - return (mCompatibilityFlags&ALWAYS_COMPAT) != 0; - } - - @Override - public String toString() { - return "CompatibilityInfo{scale=" + applicationScale + "}"; + return (mCompatibilityFlags&ALWAYS_NEEDS_COMPAT) != 0; } /** @@ -516,6 +506,28 @@ public class CompatibilityInfo implements Parcelable { } @Override + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("{"); + sb.append(applicationDensity); + sb.append("dpi"); + if (isScalingRequired()) { + sb.append(" scaling"); + } + if (!supportsScreen()) { + sb.append(" resizing"); + } + if (neverSupportsScreen()) { + sb.append(" never-compat"); + } + if (alwaysSupportsScreen()) { + sb.append(" always-compat"); + } + sb.append("}"); + return sb.toString(); + } + + @Override public int hashCode() { int result = 17; result = 31 * result + mCompatibilityFlags; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 65b3258..080cbda 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -3642,12 +3642,12 @@ public final class ActivityManagerService extends ActivityManagerNative + processName + " with config " + mConfiguration); ApplicationInfo appInfo = app.instrumentationInfo != null ? app.instrumentationInfo : app.info; + app.compat = compatibilityInfoForPackageLocked(appInfo); thread.bindApplication(processName, appInfo, providers, app.instrumentationClass, app.instrumentationProfileFile, app.instrumentationArguments, app.instrumentationWatcher, testMode, isRestrictedBackupMode || !normalMode, - mConfiguration, compatibilityInfoForPackageLocked(appInfo), - getCommonServicesLocked(), + mConfiguration, app.compat, getCommonServicesLocked(), mCoreSettingsObserver.getCoreSettingsLocked()); updateLruProcessLocked(app, false, true); app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis(); @@ -10977,13 +10977,11 @@ public final class ActivityManagerService extends ActivityManagerNative // Special case for adding a package: by default turn on compatibility // mode. } else if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) { - if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { - Uri data = intent.getData(); - String ssp; - if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { - mCompatModePackages.setPackageScreenCompatModeLocked(ssp, - ActivityManager.COMPAT_MODE_ENABLED); - } + Uri data = intent.getData(); + String ssp; + if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { + mCompatModePackages.handlePackageAddedLocked(ssp, + intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)); } } diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index d27cbda..33c12f4 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -24,6 +24,7 @@ import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; import android.os.Build; @@ -78,6 +79,7 @@ class ActivityRecord extends IApplicationToken.Stub { long startTime; // last time this activity was started long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity Configuration configuration; // configuration activity was last running in + CompatibilityInfo compat;// last used compatibility mode ActivityRecord resultTo; // who started this entry, so will get our reply final String resultWho; // additional identifier for use by resultTo. final int requestCode; // code given by requester (resultTo) @@ -137,6 +139,7 @@ class ActivityRecord extends IApplicationToken.Stub { pw.print(" componentSpecified="); pw.print(componentSpecified); pw.print(" isHomeActivity="); pw.println(isHomeActivity); pw.print(prefix); pw.print("config="); pw.println(configuration); + pw.print(prefix); pw.print("compat="); pw.println(compat); if (resultTo != null || resultWho != null) { pw.print(prefix); pw.print("resultTo="); pw.print(resultTo); pw.print(" resultWho="); pw.print(resultWho); diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index a704f88..65ea4f4 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -546,10 +546,10 @@ public class ActivityStack { r.sleeping = false; r.forceNewConfig = false; showAskCompatModeDialogLocked(r); + r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo); app.thread.scheduleLaunchActivity(new Intent(r.intent), r, System.identityHashCode(r), - r.info, mService.compatibilityInfoForPackageLocked(r.info.applicationInfo), - r.icicle, results, newIntents, !andResume, + r.info, r.compat, r.icicle, results, newIntents, !andResume, mService.isNextTransitionForward()); if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java index 221b59b..8949f48 100644 --- a/services/java/com/android/server/am/CompatModePackages.java +++ b/services/java/com/android/server/am/CompatModePackages.java @@ -17,6 +17,7 @@ import com.android.internal.util.FastXmlSerializer; import android.app.ActivityManager; import android.app.AppGlobals; +import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.res.CompatibilityInfo; @@ -117,6 +118,37 @@ public class CompatModePackages { return flags != null ? flags : 0; } + public void handlePackageAddedLocked(String packageName, boolean updated) { + ApplicationInfo ai = null; + try { + ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0); + } catch (RemoteException e) { + } + if (ai == null) { + return; + } + CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai); + final boolean mayCompat = !ci.alwaysSupportsScreen() + && !ci.neverSupportsScreen(); + + if (!updated) { + // First time -- if the app may run in compat mode, enable that + // by default. + if (mayCompat) { + setPackageScreenCompatModeLocked(ai, ActivityManager.COMPAT_MODE_ENABLED); + } + } else { + // Update -- if the app no longer can run in compat mode, clear + // any current settings for it. + if (!mayCompat && mPackages.containsKey(packageName)) { + mPackages.remove(packageName); + mHandler.removeMessages(MSG_WRITE); + Message msg = mHandler.obtainMessage(MSG_WRITE); + mHandler.sendMessageDelayed(msg, 10000); + } + } + } + public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) { return new CompatibilityInfo(ai, mService.mConfiguration.screenLayout, mService.mConfiguration.smallestScreenWidthDp, @@ -242,28 +274,47 @@ public class CompatModePackages { newFlags &= ~COMPAT_FLAG_ENABLED; } + CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai); + if (ci.alwaysSupportsScreen()) { + Slog.w(TAG, "Ignoring compat mode change of " + packageName + + "; compatibility never needed"); + newFlags = 0; + } + if (ci.neverSupportsScreen()) { + Slog.w(TAG, "Ignoring compat mode change of " + packageName + + "; compatibility always needed"); + newFlags = 0; + } + if (newFlags != curFlags) { if (newFlags != 0) { mPackages.put(packageName, newFlags); } else { mPackages.remove(packageName); } - CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai); - if (ci.alwaysSupportsScreen()) { - Slog.w(TAG, "Ignoring compat mode change of " + packageName - + "; compatibility never needed"); - return; - } - if (ci.neverSupportsScreen()) { - Slog.w(TAG, "Ignoring compat mode change of " + packageName - + "; compatibility always needed"); - return; - } + + // Need to get compatibility info in new state. + ci = compatibilityInfoForPackageLocked(ai); mHandler.removeMessages(MSG_WRITE); Message msg = mHandler.obtainMessage(MSG_WRITE); mHandler.sendMessageDelayed(msg, 10000); + ActivityRecord starting = mService.mMainStack.topRunningActivityLocked(null); + + // All activities that came from the package must be + // restarted as if there was a config change. + for (int i=mService.mMainStack.mHistory.size()-1; i>=0; i--) { + ActivityRecord a = (ActivityRecord)mService.mMainStack.mHistory.get(i); + if (a.info.packageName.equals(packageName)) { + a.forceNewConfig = true; + if (starting != null && a == starting && a.visible) { + a.startFreezingScreenLocked(starting.app, + ActivityInfo.CONFIG_SCREEN_LAYOUT); + } + } + } + // Tell all processes that loaded this package about the change. for (int i=mService.mLruProcesses.size()-1; i>=0; i--) { ProcessRecord app = mService.mLruProcesses.get(i); @@ -280,16 +331,6 @@ public class CompatModePackages { } } - // All activities that came from the packge must be - // restarted as if there was a config change. - for (int i=mService.mMainStack.mHistory.size()-1; i>=0; i--) { - ActivityRecord a = (ActivityRecord)mService.mMainStack.mHistory.get(i); - if (a.info.packageName.equals(packageName)) { - a.forceNewConfig = true; - } - } - - ActivityRecord starting = mService.mMainStack.topRunningActivityLocked(null); if (starting != null) { mService.mMainStack.ensureActivityConfigurationLocked(starting, 0); // And we need to make sure at this point that all other activities diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index a63ffae..5465e37 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -69,6 +69,7 @@ class ProcessRecord { IBinder forcingToForeground;// Token that is forcing this process to be foreground int adjSeq; // Sequence id for identifying oom_adj assignment cycles int lruSeq; // Sequence id for identifying LRU update cycles + CompatibilityInfo compat; // last used compatibility mode ComponentName instrumentationClass;// class installed to instrument app ApplicationInfo instrumentationInfo; // the application being instrumented String instrumentationProfileFile; // where to save profiling @@ -145,6 +146,7 @@ class ProcessRecord { pw.print(" publicDir="); pw.print(info.publicSourceDir); pw.print(" data="); pw.println(info.dataDir); pw.print(prefix); pw.print("packageList="); pw.println(pkgList); + pw.print(prefix); pw.print("compat="); pw.println(compat); if (instrumentationClass != null || instrumentationProfileFile != null || instrumentationArguments != null) { pw.print(prefix); pw.print("instrumentationClass="); |
