Merge "resolved conflicts for merge of 05be6d6f to master"
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index b073004..5c8abe4 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -106,6 +106,8 @@
             runDumpHeap();
         } else if (op.equals("monitor")) {
             runMonitor();
+        } else if (op.equals("screen-compat")) {
+            runScreenCompat();
         } else {
             throw new IllegalArgumentException("Unknown command: " + op);
         }
@@ -776,6 +778,29 @@
         controller.run();
     }
 
+    private void runScreenCompat() throws Exception {
+        String mode = nextArgRequired();
+        boolean enabled;
+        if ("on".equals(mode)) {
+            enabled = true;
+        } else if ("off".equals(mode)) {
+            enabled = false;
+        } else {
+            System.err.println("Error: enabled mode must be 'on' or 'off' at " + mode);
+            showUsage();
+            return;
+        }
+
+        String packageName = nextArgRequired();
+        do {
+            try {
+                mAm.setPackageScreenCompatMode(packageName, enabled);
+            } catch (RemoteException e) {
+            }
+            packageName = nextArg();
+        } while (packageName != null);
+    }
+
     private class IntentReceiver extends IIntentReceiver.Stub {
         private boolean mFinished = false;
 
@@ -956,6 +981,8 @@
                 "    start monitoring: am monitor [--gdb <port>]\n" +
                 "        --gdb: start gdbserv on the given port at crash/ANR\n" +
                 "\n" +
+                "    control screen compatibility: am screen-compat [on|off] [package]\n" +
+                "\n" +
                 "    <INTENT> specifications include these flags:\n" +
                 "        [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
                 "        [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 4b09b34c..5ffaee7 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1397,6 +1397,16 @@
             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;
+        }
+        
         case SWITCH_USER_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int userid = data.readInt();
@@ -3172,6 +3182,19 @@
         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();
+    }
+
     public boolean switchUser(int userid) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 79552bf..f0e7e98 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -202,7 +202,7 @@
 
     Bundle mCoreSettings = null;
 
-    private static final class ActivityClientRecord {
+    static final class ActivityClientRecord {
         IBinder token;
         int ident;
         Intent intent;
@@ -220,6 +220,7 @@
         ActivityClientRecord nextIdle;
 
         ActivityInfo activityInfo;
+        CompatibilityInfo compatInfo;
         LoadedApk packageInfo;
 
         List<ResultInfo> pendingResults;
@@ -260,7 +261,7 @@
         }
     }
 
-    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 @@
         }
     }
 
-    private static final class NewIntentData {
+    static final class NewIntentData {
         List<Intent> intents;
         IBinder token;
         public String toString() {
@@ -285,7 +286,7 @@
         }
     }
 
-    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 @@
 
         Intent intent;
         ActivityInfo info;
+        CompatibilityInfo compatInfo;
         public String toString() {
             return "ReceiverData{intent=" + intent + " packageName=" +
                     info.packageName + " resultCode=" + getResultCode()
@@ -302,8 +304,9 @@
         }
     }
 
-    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 @@
         }
     }
 
-    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 @@
         }
     }
 
-    private static final class BindServiceData {
+    static final class BindServiceData {
         IBinder token;
         Intent intent;
         boolean rebind;
@@ -332,7 +336,7 @@
         }
     }
 
-    private static final class ServiceArgsData {
+    static final class ServiceArgsData {
         IBinder token;
         boolean taskRemoved;
         int startId;
@@ -344,7 +348,7 @@
         }
     }
 
-    private static final class AppBindData {
+    static final class AppBindData {
         LoadedApk info;
         String processName;
         ApplicationInfo appInfo;
@@ -356,20 +360,21 @@
         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 {
         ParcelFileDescriptor fd;
         IBinder token;
         String prefix;
         String[] args;
     }
 
-    private static final class ResultData {
+    static final class ResultData {
         IBinder token;
         List<ResultInfo> results;
         public String toString() {
@@ -377,22 +382,27 @@
         }
     }
 
-    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;
+    }
+    
     native private void dumpGraphicsInfo(FileDescriptor fd);
 
     private final class ApplicationThread extends ApplicationThreadNative {
@@ -445,7 +455,8 @@
         // 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();
 
@@ -453,6 +464,7 @@
             r.ident = ident;
             r.intent = intent;
             r.activityInfo = info;
+            r.compatInfo = compatInfo;
             r.state = state;
 
             r.pendingResults = pendingResults;
@@ -486,33 +498,40 @@
         }
 
         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);
         }
@@ -556,7 +575,8 @@
                 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
@@ -576,6 +596,7 @@
             data.debugMode = debugMode;
             data.restrictedBackupMode = isRestrictedBackupMode;
             data.config = config;
+            data.compatInfo = compatInfo;
             queueOrSendMessage(H.BIND_APPLICATION, data);
         }
 
@@ -897,6 +918,13 @@
         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 {
@@ -939,6 +967,7 @@
         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) {
@@ -981,6 +1010,7 @@
                     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)";
@@ -992,7 +1022,7 @@
                     ActivityClientRecord r = (ActivityClientRecord)msg.obj;
 
                     r.packageInfo = getPackageInfoNoCheck(
-                            r.activityInfo.applicationInfo);
+                            r.activityInfo.applicationInfo, r.compatInfo);
                     handleLaunchActivity(r, null);
                 } break;
                 case RELAUNCH_ACTIVITY: {
@@ -1066,7 +1096,7 @@
                     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;
@@ -1119,6 +1149,8 @@
                 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);
         }
@@ -1329,7 +1361,8 @@
         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) {
@@ -1363,13 +1396,14 @@
         }
 
         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
@@ -1388,14 +1422,27 @@
                 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;
@@ -1413,7 +1460,7 @@
                                 ? 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) {
@@ -1470,7 +1517,8 @@
             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));
@@ -1485,7 +1533,8 @@
     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);
         }
     }
 
@@ -1635,7 +1684,7 @@
 
         ActivityInfo aInfo = r.activityInfo;
         if (r.packageInfo == null) {
-            r.packageInfo = getPackageInfo(aInfo.applicationInfo,
+            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                     Context.CONTEXT_INCLUDE_CODE);
         }
 
@@ -1859,7 +1908,7 @@
         String component = data.intent.getComponent().getClassName();
 
         LoadedApk packageInfo = getPackageInfoNoCheck(
-                data.info.applicationInfo);
+                data.info.applicationInfo, data.compatInfo);
 
         IActivityManager mgr = ActivityManagerNative.getDefault();
 
@@ -1920,7 +1969,7 @@
         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
@@ -1982,7 +2031,7 @@
     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) {
@@ -2004,7 +2053,7 @@
         unscheduleGcIdler();
 
         LoadedApk packageInfo = getPackageInfoNoCheck(
-                data.info.applicationInfo);
+                data.info.applicationInfo, data.compatInfo);
         Service service = null;
         try {
             java.lang.ClassLoader cl = packageInfo.getClassLoader();
@@ -2721,6 +2770,18 @@
         }
     }
 
+    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++) {
@@ -3058,7 +3119,7 @@
         
         // If there was a pending configuration change, execute it first.
         if (changedConfig != null) {
-            handleConfigurationChanged(changedConfig);
+            handleConfigurationChanged(changedConfig, null);
         }
 
         ActivityClientRecord r = mActivities.get(tmp.token);
@@ -3228,11 +3289,12 @@
         }
     }
 
-    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;
@@ -3245,7 +3307,7 @@
             Locale.setDefault(config.locale);
         }
 
-        Resources.updateSystemConfiguration(config, dm);
+        Resources.updateSystemConfiguration(config, dm, compat);
 
         ApplicationPackageManager.configurationChanged();
         //Slog.i(TAG, "Configuration changed in " + currentPackageName());
@@ -3260,7 +3322,7 @@
             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 {
@@ -3272,7 +3334,7 @@
         return changes != 0;
     }
     
-    final void handleConfigurationChanged(Configuration config) {
+    final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {
 
         ArrayList<ComponentCallbacks> callbacks = null;
 
@@ -3291,15 +3353,21 @@
             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);
         }
@@ -3446,9 +3514,10 @@
          * 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
@@ -3540,7 +3609,7 @@
             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);
@@ -3954,7 +4023,7 @@
                     // 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 0e511f2..dc0f529 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -23,6 +23,7 @@
 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 @@
             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 @@
             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 @@
             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;
         }
 
@@ -257,12 +261,13 @@
             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;
         }
         
@@ -390,8 +395,9 @@
         {
             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;
         }
 
@@ -399,7 +405,8 @@
         {
             data.enforceInterface(IApplicationThread.descriptor);
             ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(data);
-            scheduleDestroyBackupAgent(appInfo);
+            CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
+            scheduleDestroyBackupAgent(appInfo, compatInfo);
             return true;
         }
 
@@ -457,12 +464,20 @@
             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);
@@ -555,7 +570,8 @@
     }
 
     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();
@@ -564,6 +580,7 @@
         data.writeStrongBinder(token);
         data.writeInt(ident);
         info.writeToParcel(data, 0);
+        compatInfo.writeToParcel(data, 0);
         data.writeBundle(state);
         data.writeTypedList(pendingResults);
         data.writeTypedList(pendingNewIntents);
@@ -620,12 +637,13 @@
     }
     
     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);
@@ -635,32 +653,36 @@
         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();
@@ -721,7 +743,7 @@
     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);
@@ -740,6 +762,7 @@
         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,
@@ -954,6 +977,16 @@
         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 @@
         }
 
         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 @@
                         " 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 bec697a..994a924 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -342,6 +342,9 @@
     public int startActivitiesInPackage(int uid,
             Intent[] intents, String[] resolvedTypes, IBinder resultTo) throws RemoteException;
 
+    public void setPackageScreenCompatMode(String packageName, boolean compatEnabled)
+            throws RemoteException;
+    
     // Multi-user APIs
     public boolean switchUser(int userid) throws RemoteException;
     
@@ -564,7 +567,8 @@
     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 SWITCH_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+123;
-    int REMOVE_SUB_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+124;
-    int REMOVE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+125;
+    int SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+123;
+    int SWITCH_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+124;
+    int REMOVE_SUB_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+125;
+    int REMOVE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+126;
 }
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index b29b088..8c31559 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -23,6 +23,7 @@
 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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     }
 
     public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
+            CompatibilityInfo compatInfo,
             ActivityThread mainThread, ClassLoader baseLoader,
             boolean securityViolation, boolean includeCode) {
         mActivityThread = activityThread;
@@ -114,7 +115,7 @@
         mBaseClassLoader = baseLoader;
         mSecurityViolation = securityViolation;
         mIncludeCode = includeCode;
-        mCompatibilityInfo = new CompatibilityInfo(aInfo);
+        mCompatibilityInfo = compatInfo;
 
         if (mAppDir == null) {
             if (ActivityThread.mSystemContext == null) {
@@ -122,7 +123,8 @@
                     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 @@
     }
 
     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 @@
         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.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 @@
  * 
  *  {@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 @@
     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 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 ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
-            mCompatibilityFlags |= EXPANDABLE | CONFIGURED_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 (supportsScreen) {
+            compatFlags &= ~NEEDS_SCREEN_COMPAT;
+        } else {
+            compatFlags |= NEEDS_SCREEN_COMPAT;
         }
         
         if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
@@ -165,13 +160,14 @@
             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 @@
     }
 
     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 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 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 {
-            int xOffset = (width - portraitWidth) / 2 ;
-            outRect.set(xOffset, 0, xOffset + portraitWidth, portraitHeight);
+            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 {
+            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 93b3429..0de08f2 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -814,12 +814,22 @@
     }
     
     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
-                + this.screenWidthDp + this.screenHeightDp;
+        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;
+        result = 31 * result + screenWidthDp;
+        result = 31 * result + screenHeightDp;
+        return result;
     }
 }
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 2e6ae70..540f704 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -92,6 +92,7 @@
     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
@@ -1401,10 +1402,23 @@
      */
     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);
                 configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
             }
             if (mConfiguration.locale == null) {
@@ -1412,8 +1426,7 @@
             }
             if (metrics != null) {
                 mMetrics.setTo(metrics);
-                mMetrics.updateMetrics(mCompatibilityInfo,
-                        mConfiguration.orientation, mConfiguration.screenLayout);
+                mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
             }
             mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
 
@@ -1503,15 +1516,23 @@
      *
      * @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 float ydpi;
 
+    /** @hide */
+    public int realWidthPixels;
+    /** @hide */
+    public int realHeightPixels;
+
     public DisplayMetrics() {
     }
     
@@ -118,6 +121,8 @@
         scaledDensity = o.scaledDensity;
         xdpi = o.xdpi;
         ydpi = o.ydpi;
+        realWidthPixels = o.realWidthPixels;
+        realHeightPixels = o.realHeightPixels;
     }
     
     public void setToDefaults() {
@@ -128,101 +133,8 @@
         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 8e839c0..1d60066 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -226,6 +226,9 @@
         outMetrics.scaledDensity= outMetrics.density;
         outMetrics.xdpi         = mDpiX;
         outMetrics.ydpi         = mDpiY;
+
+        outMetrics.realWidthPixels  = outMetrics.widthPixels;
+        outMetrics.realHeightPixels = outMetrics.heightPixels;
     }
 
     static IWindowManager getWindowManager() {
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 3d19380..5a418f3 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -466,6 +466,18 @@
     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.
      */
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 9b92c73..c7ebf56 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -216,6 +216,8 @@
     status_t setAxisValue(int32_t axis, float value);
     float* editAxisValue(int32_t axis);
 
+    void scale(float scale);
+
 #ifdef HAVE_ANDROID_OS
     status_t readFromParcel(Parcel* parcel);
     status_t writeToParcel(Parcel* parcel) const;
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index a95f432..d811dd7 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -302,6 +302,24 @@
     return &values[index];
 }
 
+static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) {
+    float* value = c.editAxisValue(axis);
+    if (value) {
+        *value *= scaleFactor;
+    }
+}
+
+void PointerCoords::scale(float scaleFactor) {
+    // No need to scale pressure or size since they are normalized.
+    // No need to scale orientation since it is meaningless to do so.
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor);
+    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
+}
+
 #ifdef HAVE_ANDROID_OS
 status_t PointerCoords::readFromParcel(Parcel* parcel) {
     bits = parcel->readInt64();
@@ -436,11 +454,9 @@
     float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis);
     switch (axis) {
     case AMOTION_EVENT_AXIS_X:
-        value += mXOffset;
-        break;
+        return value + mXOffset;
     case AMOTION_EVENT_AXIS_Y:
-        value += mYOffset;
-        break;
+        return value + mYOffset;
     }
     return value;
 }
@@ -460,11 +476,9 @@
     float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
     switch (axis) {
     case AMOTION_EVENT_AXIS_X:
-        value += mXOffset;
-        break;
+        return value + mXOffset;
     case AMOTION_EVENT_AXIS_Y:
-        value += mYOffset;
-        break;
+        return value + mYOffset;
     }
     return value;
 }
@@ -484,13 +498,6 @@
     mYOffset += yOffset;
 }
 
-static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) {
-    float* value = c.editAxisValue(axis);
-    if (value) {
-        *value *= scaleFactor;
-    }
-}
-
 void MotionEvent::scale(float scaleFactor) {
     mXOffset *= scaleFactor;
     mYOffset *= scaleFactor;
@@ -499,15 +506,7 @@
 
     size_t numSamples = mSamplePointerCoords.size();
     for (size_t i = 0; i < numSamples; i++) {
-        PointerCoords& c = mSamplePointerCoords.editItemAt(i);
-        // No need to scale pressure or size since they are normalized.
-        // No need to scale orientation since it is meaningless to do so.
-        scaleAxisValue(c, AMOTION_EVENT_AXIS_X, scaleFactor);
-        scaleAxisValue(c, AMOTION_EVENT_AXIS_Y, scaleFactor);
-        scaleAxisValue(c, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor);
-        scaleAxisValue(c, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor);
-        scaleAxisValue(c, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor);
-        scaleAxisValue(c, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
+        mSamplePointerCoords.editItemAt(i).scale(scaleFactor);
     }
 }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 6632f34..9ca153e 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -230,6 +230,7 @@
     boolean mSafeMode;
     WindowState mStatusBar = null;
     boolean mStatusBarCanHide;
+    int mScreenMarginBottom;
     final ArrayList<WindowState> mStatusBarPanels = new ArrayList<WindowState>();
     WindowState mNavigationBar = null;
 
@@ -1070,6 +1071,14 @@
         return STATUS_BAR_LAYER;
     }
 
+    public int getNonDecorDisplayWidth(int fullWidth) {
+        return fullWidth;
+    }
+
+    public int getNonDecorDisplayHeight(int fullHeight) {
+        return fullHeight - mScreenMarginBottom;
+    }
+
     public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
         return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD;
     }
@@ -1219,6 +1228,8 @@
                 // The Configuration will be stable by now, so we can load this
                 mStatusBarCanHide = mContext.getResources().getBoolean(
                         com.android.internal.R.bool.config_statusBarCanHide);
+                mScreenMarginBottom = mContext.getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.screen_margin_bottom);
 
                 break;
             case TYPE_NAVIGATION_BAR:
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 46de933..d97a9be 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -177,6 +177,14 @@
     return true;
 }
 
+static void scalePointerCoords(const PointerCoords* inCoords, size_t count, float scaleFactor,
+        PointerCoords* outCoords) {
+   for (size_t i = 0; i < count; i++) {
+       outCoords[i] = inCoords[i];
+       outCoords[i].scale(scaleFactor);
+   }
+}
+
 static void dumpRegion(String8& dump, const SkRegion& region) {
     if (region.isEmpty()) {
         dump.append("<empty>");
@@ -1603,6 +1611,7 @@
     target.flags = targetFlags;
     target.xOffset = - window->frameLeft;
     target.yOffset = - window->frameTop;
+    target.scaleFactor = window->scaleFactor;
     target.pointerIds = pointerIds;
 }
 
@@ -1616,6 +1625,7 @@
         target.xOffset = 0;
         target.yOffset = 0;
         target.pointerIds.clear();
+        target.scaleFactor = 1.0f;
     }
 }
 
@@ -1717,12 +1727,12 @@
         bool resumeWithAppendedMotionSample) {
 #if DEBUG_DISPATCH_CYCLE
     LOGD("channel '%s' ~ prepareDispatchCycle - flags=%d, "
-            "xOffset=%f, yOffset=%f, "
+            "xOffset=%f, yOffset=%f, scaleFactor=%f"
             "pointerIds=0x%x, "
             "resumeWithAppendedMotionSample=%s",
             connection->getInputChannelName(), inputTarget->flags,
             inputTarget->xOffset, inputTarget->yOffset,
-            inputTarget->pointerIds.value,
+            inputTarget->scaleFactor, inputTarget->pointerIds.value,
             toString(resumeWithAppendedMotionSample));
 #endif
 
@@ -1803,8 +1813,19 @@
             // consumed the motion event (or if the channel is broken).
             MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
             MotionSample* appendedMotionSample = motionEntry->lastSample;
-            status_t status = connection->inputPublisher.appendMotionSample(
-                    appendedMotionSample->eventTime, appendedMotionSample->pointerCoords);
+            status_t status;
+            if (motionEventDispatchEntry->scaleFactor == 1.0f) {
+                status = connection->inputPublisher.appendMotionSample(
+                        appendedMotionSample->eventTime, appendedMotionSample->pointerCoords);
+            } else {
+                PointerCoords scaledCoords[MAX_POINTERS];
+                for (size_t i = 0; i < motionEntry->pointerCount; i++) {
+                    scaledCoords[i] = appendedMotionSample->pointerCoords[i];
+                    scaledCoords[i].scale(motionEventDispatchEntry->scaleFactor);
+                }
+                status = connection->inputPublisher.appendMotionSample(
+                        appendedMotionSample->eventTime, scaledCoords);
+            }
             if (status == OK) {
 #if DEBUG_BATCHING
                 LOGD("channel '%s' ~ Successfully streamed new motion sample.",
@@ -1867,7 +1888,8 @@
     // This is a new event.
     // Enqueue a new dispatch entry onto the outbound queue for this connection.
     DispatchEntry* dispatchEntry = mAllocator.obtainDispatchEntry(eventEntry, // increments ref
-            inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset);
+            inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
+            inputTarget->scaleFactor);
     if (dispatchEntry->hasForegroundTarget()) {
         incrementPendingForegroundDispatchesLocked(eventEntry);
     }
@@ -1961,14 +1983,26 @@
             firstMotionSample = & motionEntry->firstSample;
         }
 
+        PointerCoords scaledCoords[MAX_POINTERS];
+        const PointerCoords* usingCoords = firstMotionSample->pointerCoords;
+
         // Set the X and Y offset depending on the input source.
-        float xOffset, yOffset;
+        float xOffset, yOffset, scaleFactor;
         if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
-            xOffset = dispatchEntry->xOffset;
-            yOffset = dispatchEntry->yOffset;
+            scaleFactor = dispatchEntry->scaleFactor;
+            xOffset = dispatchEntry->xOffset * scaleFactor;
+            yOffset = dispatchEntry->yOffset * scaleFactor;
+            if (scaleFactor != 1.0f) {
+                for (size_t i = 0; i < motionEntry->pointerCount; i++) {
+                    scaledCoords[i] = firstMotionSample->pointerCoords[i];
+                    scaledCoords[i].scale(scaleFactor);
+                }
+                usingCoords = scaledCoords;
+            }
         } else {
             xOffset = 0.0f;
             yOffset = 0.0f;
+            scaleFactor = 1.0f;
         }
 
         // Update the connection's input state.
@@ -1977,11 +2011,9 @@
         // Publish the motion event and the first motion sample.
         status = connection->inputPublisher.publishMotionEvent(motionEntry->deviceId,
                 motionEntry->source, action, flags, motionEntry->edgeFlags, motionEntry->metaState,
-                xOffset, yOffset,
-                motionEntry->xPrecision, motionEntry->yPrecision,
+                xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
                 motionEntry->downTime, firstMotionSample->eventTime,
-                motionEntry->pointerCount, motionEntry->pointerIds,
-                firstMotionSample->pointerCoords);
+                motionEntry->pointerCount, motionEntry->pointerIds, usingCoords);
 
         if (status) {
             LOGE("channel '%s' ~ Could not publish motion event, "
@@ -1996,7 +2028,7 @@
             MotionSample* nextMotionSample = firstMotionSample->next;
             for (; nextMotionSample != NULL; nextMotionSample = nextMotionSample->next) {
                 status = connection->inputPublisher.appendMotionSample(
-                        nextMotionSample->eventTime, nextMotionSample->pointerCoords);
+                        nextMotionSample->eventTime, usingCoords);
                 if (status == NO_MEMORY) {
 #if DEBUG_DISPATCH_CYCLE
                     LOGD("channel '%s' ~ Shared memory buffer full.  Some motion samples will "
@@ -2234,18 +2266,21 @@
             }
 
             int32_t xOffset, yOffset;
+            float scaleFactor;
             const InputWindow* window = getWindowLocked(connection->inputChannel);
             if (window) {
                 xOffset = -window->frameLeft;
                 yOffset = -window->frameTop;
+                scaleFactor = window->scaleFactor;
             } else {
                 xOffset = 0;
                 yOffset = 0;
+                scaleFactor = 1.0f;
             }
 
             DispatchEntry* cancelationDispatchEntry =
                     mAllocator.obtainDispatchEntry(cancelationEventEntry, // increments ref
-                    0, xOffset, yOffset);
+                    0, xOffset, yOffset, scaleFactor);
             connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry);
 
             mAllocator.releaseEventEntry(cancelationEventEntry);
@@ -3244,7 +3279,7 @@
             const InputWindow& window = mWindows[i];
             dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, "
                     "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
-                    "frame=[%d,%d][%d,%d], "
+                    "frame=[%d,%d][%d,%d], scale=%f, "
                     "touchableRegion=",
                     i, window.name.string(),
                     toString(window.paused),
@@ -3255,7 +3290,8 @@
                     window.layoutParamsFlags, window.layoutParamsType,
                     window.layer,
                     window.frameLeft, window.frameTop,
-                    window.frameRight, window.frameBottom);
+                    window.frameRight, window.frameBottom,
+                    window.scaleFactor);
             dumpRegion(dump, window.touchableRegion);
             dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
                     window.ownerPid, window.ownerUid,
@@ -3803,13 +3839,14 @@
 
 InputDispatcher::DispatchEntry* InputDispatcher::Allocator::obtainDispatchEntry(
         EventEntry* eventEntry,
-        int32_t targetFlags, float xOffset, float yOffset) {
+        int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) {
     DispatchEntry* entry = mDispatchEntryPool.alloc();
     entry->eventEntry = eventEntry;
     eventEntry->refCount += 1;
     entry->targetFlags = targetFlags;
     entry->xOffset = xOffset;
     entry->yOffset = yOffset;
+    entry->scaleFactor = scaleFactor;
     entry->inProgress = false;
     entry->headMotionSample = NULL;
     entry->tailMotionSample = NULL;
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index af0153b..96ece32 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -132,6 +132,10 @@
     // (ignored for KeyEvents)
     float xOffset, yOffset;
 
+    // Scaling factor to apply to MotionEvent as it is delivered.
+    // (ignored for KeyEvents)
+    float scaleFactor;
+
     // The subset of pointer ids to include in motion events dispatched to this input target
     // if FLAG_SPLIT is set.
     BitSet32 pointerIds;
@@ -474,6 +478,7 @@
         int32_t targetFlags;
         float xOffset;
         float yOffset;
+        float scaleFactor;
 
         // True if dispatch has started.
         bool inProgress;
@@ -602,7 +607,7 @@
                 nsecs_t downTime, uint32_t pointerCount,
                 const int32_t* pointerIds, const PointerCoords* pointerCoords);
         DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry,
-                int32_t targetFlags, float xOffset, float yOffset);
+                int32_t targetFlags, float xOffset, float yOffset, float scaleFactor);
         CommandEntry* obtainCommandEntry(Command command);
 
         void releaseInjectionState(InjectionState* injectionState);
diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp
index b552f6d..ccea9e4 100644
--- a/services/input/InputWindow.cpp
+++ b/services/input/InputWindow.cpp
@@ -29,8 +29,7 @@
 }
 
 bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const {
-    return x >= frameLeft && x <= frameRight
-            && y >= frameTop && y <= frameBottom;
+    return x <= frameRight || y <= frameBottom;
 }
 
 bool InputWindow::isTrustedOverlay() const {
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index 208353d..cde7294 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -133,6 +133,7 @@
     int32_t frameTop;
     int32_t frameRight;
     int32_t frameBottom;
+    float scaleFactor;
     SkRegion touchableRegion;
     bool visible;
     bool canReceiveKeys;
@@ -146,6 +147,11 @@
     bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
     bool frameContainsPoint(int32_t x, int32_t y) const;
 
+    /* These use the globalScale to convert a given screen offset to the
+     * corresponding location within the window.
+     */
+    int32_t displayToWindowX(int32_t x) const;
+
     /* Returns true if the window is of a trusted type that is allowed to silently
      * overlay other windows for the purpose of implementing the secure views feature.
      * Trusted overlays, such as IME windows, can partly obscure other windows without causing
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index da34644..ed52dd3 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -75,6 +75,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.net.Proxy;
@@ -147,7 +148,7 @@
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
     static final String TAG = "ActivityManager";
     static final boolean DEBUG = false;
-    static final boolean localLOGV = false;
+    static final boolean localLOGV = DEBUG;
     static final boolean DEBUG_SWITCH = localLOGV || false;
     static final boolean DEBUG_TASKS = localLOGV || false;
     static final boolean DEBUG_PAUSE = localLOGV || false;
@@ -544,6 +545,12 @@
     ProcessRecord mHomeProcess;
     
     /**
+     * Packages that the user has asked to have run in screen size
+     * compatibility mode instead of filling the screen.
+     */
+    final HashSet<String> mScreenCompatPackages = new HashSet<String>();
+
+    /**
      * Set of PendingResultRecord objects that are currently active.
      */
     final HashSet mPendingResultRecords = new HashSet();
@@ -2074,6 +2081,74 @@
         }
     }
     
+    CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
+        return new CompatibilityInfo(ai, mConfiguration.screenLayout,
+                mScreenCompatPackages.contains(ai.packageName));
+    }
+
+    public void setPackageScreenCompatMode(String packageName, boolean compatEnabled) {
+        synchronized (this) {
+            ApplicationInfo ai = null;
+            try {
+                ai = AppGlobals.getPackageManager().
+                        getApplicationInfo(packageName, STOCK_PM_FLAGS);
+            } catch (RemoteException e) {
+            }
+            if (ai == null) {
+                Slog.w(TAG, "setPackageScreenCompatMode failed: unknown package " + packageName);
+                return;
+            }
+            boolean changed = false;
+            if (compatEnabled) {
+                if (!mScreenCompatPackages.contains(packageName)) {
+                    changed = true;
+                    mScreenCompatPackages.add(packageName);
+                }
+            } else {
+                if (mScreenCompatPackages.contains(packageName)) {
+                    changed = true;
+                    mScreenCompatPackages.remove(packageName);
+                }
+            }
+            if (changed) {
+                CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai);
+
+                // Tell all processes that loaded this package about the change.
+                for (int i=mLruProcesses.size()-1; i>=0; i--) {
+                    ProcessRecord app = mLruProcesses.get(i);
+                    if (!app.pkgList.contains(packageName)) {
+                        continue;
+                    }
+                    try {
+                        if (app.thread != null) {
+                            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending to proc "
+                                    + app.processName + " new compat " + ci);
+                            app.thread.updatePackageCompatibilityInfo(packageName, ci);
+                        }
+                    } catch (Exception e) {
+                    }
+                }
+
+                // All activities that came from the packge must be
+                // restarted as if there was a config change.
+                for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
+                    ActivityRecord a = (ActivityRecord)mMainStack.mHistory.get(i);
+                    if (a.info.packageName.equals(packageName)) {
+                        a.forceNewConfig = true;
+                    }
+                }
+
+                ActivityRecord starting = mMainStack.topRunningActivityLocked(null);
+                if (starting != null) {
+                    mMainStack.ensureActivityConfigurationLocked(starting, 0);
+                    // And we need to make sure at this point that all other activities
+                    // are made visible with the correct configuration.
+                    mMainStack.ensureActivitiesVisibleLocked(starting, 0);
+                }
+            }
+        }
+    }
+
     void reportResumedActivityLocked(ActivityRecord r) {
         //Slog.i(TAG, "**** REPORT RESUME: " + r);
         
@@ -3576,12 +3651,14 @@
             }
             if (DEBUG_CONFIGURATION) Slog.v(TAG, "Binding proc "
                     + processName + " with config " + mConfiguration);
-            thread.bindApplication(processName, app.instrumentationInfo != null
-                    ? app.instrumentationInfo : app.info, providers,
+            ApplicationInfo appInfo = app.instrumentationInfo != null
+                    ? app.instrumentationInfo : app.info;
+            thread.bindApplication(processName, appInfo, providers,
                     app.instrumentationClass, app.instrumentationProfileFile,
                     app.instrumentationArguments, app.instrumentationWatcher, testMode, 
                     isRestrictedBackupMode || !normalMode,
-                    mConfiguration, getCommonServicesLocked(),
+                    mConfiguration, compatibilityInfoForPackageLocked(appInfo),
+                    getCommonServicesLocked(),
                     mCoreSettingsObserver.getCoreSettingsLocked());
             updateLruProcessLocked(app, false, true);
             app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
@@ -3672,7 +3749,9 @@
             if (DEBUG_BACKUP) Slog.v(TAG, "New app is backup target, launching agent for " + app);
             ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
             try {
-                thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
+                thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
+                        compatibilityInfoForPackageLocked(mBackupTarget.appInfo),
+                        mBackupTarget.backupMode);
             } catch (Exception e) {
                 Slog.w(TAG, "Exception scheduling backup agent creation: ");
                 e.printStackTrace();
@@ -7866,6 +7945,10 @@
         pw.println("  mConfiguration: " + mConfiguration);
         if (dumpAll) {
             pw.println("  mConfigWillChange: " + mMainStack.mConfigWillChange);
+            if (mScreenCompatPackages.size() > 0) {
+                pw.print("  mScreenCompatPackages=");
+                pw.println(mScreenCompatPackages);
+            }
         }
         pw.println("  mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
         if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
@@ -9560,7 +9643,8 @@
                 r.stats.startLaunchedLocked();
             }
             ensurePackageDexOpt(r.serviceInfo.packageName);
-            app.thread.scheduleCreateService(r, r.serviceInfo);
+            app.thread.scheduleCreateService(r, r.serviceInfo,
+                    compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo));
             r.postNotification();
             created = true;
         } finally {
@@ -10670,7 +10754,8 @@
             if (proc.thread != null) {
                 if (DEBUG_BACKUP) Slog.v(TAG, "Agent proc already running: " + proc);
                 try {
-                    proc.thread.scheduleCreateBackupAgent(app, backupMode);
+                    proc.thread.scheduleCreateBackupAgent(app,
+                            compatibilityInfoForPackageLocked(app), backupMode);
                 } catch (RemoteException e) {
                     // Will time out on the backup manager side
                 }
@@ -10742,7 +10827,8 @@
             // If the app crashed during backup, 'thread' will be null here
             if (proc.thread != null) {
                 try {
-                    proc.thread.scheduleDestroyBackupAgent(appInfo);
+                    proc.thread.scheduleDestroyBackupAgent(appInfo,
+                            compatibilityInfoForPackageLocked(appInfo));
                 } catch (Exception e) {
                     Slog.e(TAG, "Exception when unbinding backup agent:");
                     e.printStackTrace();
@@ -11589,6 +11675,7 @@
                     + ": " + r);
             ensurePackageDexOpt(r.intent.getComponent().getPackageName());
             app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
+                    compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
                     r.resultCode, r.resultData, r.resultExtras, r.ordered);
             if (DEBUG_BROADCAST)  Slog.v(TAG,
                     "Process cur broadcast " + r + " DELIVERED for app " + app);
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 2703481..cc9e78e 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -109,6 +109,7 @@
     boolean hasBeenLaunched;// has this activity ever been launched?
     boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
     boolean immersive;      // immersive mode (don't interrupt if possible)
+    boolean forceNewConfig; // force re-create with new config next time
 
     String stringName;      // for caching of toString().
     
@@ -174,7 +175,8 @@
                 pw.print(" immersive="); pw.print(immersive);
                 pw.print(" launchMode="); pw.println(launchMode);
         pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
-                pw.print(" thumbnailNeeded="); pw.println(thumbnailNeeded);
+                pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded);
+                pw.print(" forceNewConfig="); pw.println(forceNewConfig);
         pw.print(prefix); pw.print("thumbHolder="); pw.println(thumbHolder);
         if (launchTime != 0 || startTime != 0) {
             pw.print(prefix); pw.print("launchTime=");
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 9558895..b0400af 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -540,9 +540,11 @@
             }
             mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
             r.sleeping = false;
+            r.forceNewConfig = false;
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
                     System.identityHashCode(r),
-                    r.info, r.icicle, results, newIntents, !andResume,
+                    r.info, mService.compatibilityInfoForPackageLocked(r.info.applicationInfo),
+                    r.icicle, results, newIntents, !andResume,
                     mService.isNextTransitionForward());
             
             if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
@@ -3856,7 +3858,7 @@
         // Short circuit: if the two configurations are the exact same
         // object (the common case), then there is nothing to do.
         Configuration newConfig = mService.mConfiguration;
-        if (r.configuration == newConfig) {
+        if (r.configuration == newConfig && !r.forceNewConfig) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
                     "Configuration unchanged in " + r);
             return true;
@@ -3881,6 +3883,7 @@
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
                     "Configuration doesn't matter not running " + r);
             r.stopFreezingScreenLocked(false);
+            r.forceNewConfig = false;
             return true;
         }
         
@@ -3892,10 +3895,11 @@
                     + Integer.toHexString(r.info.configChanges)
                     + ", newConfig=" + newConfig);
         }
-        if ((changes&(~r.info.configChanges)) != 0) {
+        if ((changes&(~r.info.configChanges)) != 0 || r.forceNewConfig) {
             // Aha, the activity isn't handling the change, so DIE DIE DIE.
             r.configChangeFlags |= changes;
             r.startFreezingScreenLocked(r.app, globalChanges);
+            r.forceNewConfig = false;
             if (r.app == null || r.app.thread == null) {
                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
                         "Switch is destroying non-running " + r);
@@ -3966,6 +3970,7 @@
         
         try {
             if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
+            r.forceNewConfig = false;
             r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
                     changes, !andResume, mService.mConfiguration);
             // Note: don't need to call pauseIfSleepingLocked() here, because
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index e39c239..5be35ee 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -24,6 +24,7 @@
 import android.app.IInstrumentationWatcher;
 import android.content.ComponentName;
 import android.content.pm.ApplicationInfo;
+import android.content.res.CompatibilityInfo;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.SystemClock;
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 4f157fe..a3e8be0 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -205,12 +205,21 @@
             inputWindow.ownerPid = child.mSession.mPid;
             inputWindow.ownerUid = child.mSession.mUid;
             
-            final Rect frame = child.mFrame;
+            final Rect frame = child.mScaledFrame;
             inputWindow.frameLeft = frame.left;
             inputWindow.frameTop = frame.top;
             inputWindow.frameRight = frame.right;
             inputWindow.frameBottom = frame.bottom;
 
+            if (child.mGlobalScale != 1) {
+                // If we are scaling the window, input coordinates need
+                // to be inversely scaled to map from what is on screen
+                // to what is actually being touched in the UI.
+                inputWindow.scaleFactor = 1.0f/child.mGlobalScale;
+            } else {
+                inputWindow.scaleFactor = 1;
+            }
+
             child.getTouchableRegion(inputWindow.touchableRegion);
         }
 
diff --git a/services/java/com/android/server/wm/InputWindow.java b/services/java/com/android/server/wm/InputWindow.java
index e3eb473..578120e 100644
--- a/services/java/com/android/server/wm/InputWindow.java
+++ b/services/java/com/android/server/wm/InputWindow.java
@@ -46,6 +46,10 @@
     public int frameRight;
     public int frameBottom;
 
+    // Global scaling factor applied to touch events when they are dispatched
+    // to the window
+    public float scaleFactor;
+
     // Window touchable region.
     public final Region touchableRegion = new Region();
 
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 8b739a4..12a5000 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -19,7 +19,6 @@
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
-import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -589,6 +588,7 @@
 
     // The frame use to limit the size of the app running in compatibility mode.
     Rect mCompatibleScreenFrame = new Rect();
+    float mCompatibleScreenScale;
     // The surface used to fill the outer rim of the app running in compatibility mode.
     Surface mBackgroundFillerSurface = null;
     WindowState mBackgroundFillerTarget = null;
@@ -1760,7 +1760,7 @@
         boolean rawChanged = false;
         float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : 0.5f;
         float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
-        int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw;
+        int availw = wallpaperWin.mScaledFrame.right-wallpaperWin.mScaledFrame.left-dw;
         int offset = availw > 0 ? -(int)(availw*wpx+.5f) : 0;
         changed = wallpaperWin.mXOffset != offset;
         if (changed) {
@@ -2889,14 +2889,14 @@
     }
 
     private boolean applyAnimationLocked(AppWindowToken wtoken,
-            WindowManager.LayoutParams lp, int transit, boolean enter) {
+            WindowManager.LayoutParams lp, int transit, boolean enter, boolean bgFiller) {
         // Only apply an animation if the display isn't frozen.  If it is
         // frozen, there is no reason to animate and it can cause strange
         // artifacts when we unfreeze the display if some different animation
         // is running.
         if (!mDisplayFrozen && mPolicy.isScreenOn()) {
             Animation a;
-            if (lp != null && (lp.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
+            if (bgFiller) {
                 a = new FadeInOutAnimation(enter);
                 if (DEBUG_ANIM) Slog.v(TAG,
                         "applying FadeInOutAnimation for a window in compatibility mode");
@@ -3682,7 +3682,7 @@
     }
 
     boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
-            boolean visible, int transit, boolean performLayout) {
+            boolean visible, int transit, boolean performLayout, boolean bgFiller) {
         boolean delayed = false;
 
         if (wtoken.clientHidden == visible) {
@@ -3704,7 +3704,7 @@
                 if (wtoken.animation == sDummyAnimation) {
                     wtoken.animation = null;
                 }
-                applyAnimationLocked(wtoken, lp, transit, visible);
+                applyAnimationLocked(wtoken, lp, transit, visible, bgFiller);
                 changed = true;
                 if (wtoken.animation != null) {
                     delayed = runningAppAnimation = true;
@@ -3857,7 +3857,8 @@
             }
 
             final long origId = Binder.clearCallingIdentity();
-            setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_UNSET, true);
+            setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_UNSET,
+                    true, false);
             wtoken.updateReportedVisibilityLocked();
             Binder.restoreCallingIdentity(origId);
         }
@@ -3983,7 +3984,8 @@
             WindowToken basewtoken = mTokenMap.remove(token);
             if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken);
-                delayed = setTokenVisibilityLocked(wtoken, null, false, WindowManagerPolicy.TRANSIT_UNSET, true);
+                delayed = setTokenVisibilityLocked(wtoken, null, false,
+                        WindowManagerPolicy.TRANSIT_UNSET, true, false);
                 wtoken.inPendingTransaction = false;
                 mOpeningApps.remove(wtoken);
                 wtoken.waitingToShow = false;
@@ -4759,8 +4761,8 @@
         synchronized(mWindowMap) {
             long ident = Binder.clearCallingIdentity();
 
-            dw = mCurDisplayWidth;
-            dh = mCurDisplayHeight;
+            dw = mPolicy.getNonDecorDisplayWidth(mCurDisplayWidth);
+            dh = mPolicy.getNonDecorDisplayHeight(mCurDisplayHeight);
 
             int aboveAppLayer = mPolicy.windowTypeToLayerLw(
                     WindowManager.LayoutParams.TYPE_APPLICATION) * TYPE_LAYER_MULTIPLIER
@@ -4808,7 +4810,7 @@
                 
                 // Don't include wallpaper in bounds calculation
                 if (!ws.mIsWallpaper) {
-                    final Rect wf = ws.mFrame;
+                    final Rect wf = ws.mScaledFrame;
                     final Rect cr = ws.mContentInsets;
                     int left = wf.left + cr.left;
                     int top = wf.top + cr.top;
@@ -5526,10 +5528,11 @@
 
         // Override display width and height with what we are computing,
         // to be sure they remain consistent.
-        dm.widthPixels = dw;
-        dm.heightPixels = dh;
+        dm.widthPixels = mPolicy.getNonDecorDisplayWidth(dw);
+        dm.heightPixels = mPolicy.getNonDecorDisplayHeight(dh);
 
-        CompatibilityInfo.updateCompatibleScreenFrame(dm, orientation, mCompatibleScreenFrame);
+        mCompatibleScreenScale = CompatibilityInfo.updateCompatibleScreenFrame(
+                dm, mCompatibleScreenFrame, null);
 
         config.screenWidthDp = (int)(dm.widthPixels / dm.density);
         config.screenHeightDp = (int)(dm.heightPixels / dm.density);
@@ -6680,6 +6683,9 @@
         final int dw = mCurDisplayWidth;
         final int dh = mCurDisplayHeight;
 
+        final int innerDw = mPolicy.getNonDecorDisplayWidth(dw);
+        final int innerDh = mPolicy.getNonDecorDisplayHeight(dh);
+
         final int N = mWindows.size();
         int i;
 
@@ -6732,7 +6738,9 @@
                         //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
                         win.mContentChanged = false;
                     }
+                    win.prelayout();
                     mPolicy.layoutWindowLw(win, win.mAttrs, null);
+                    win.evalNeedsBackgroundFiller(innerDw, innerDh);
                     win.mLayoutSeq = seq;
                     if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
                             + win.mFrame + " mContainingFrame="
@@ -6767,7 +6775,9 @@
                         //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
                         win.mContentChanged = false;
                     }
+                    win.prelayout();
                     mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
+                    win.evalNeedsBackgroundFiller(innerDw, innerDh);
                     win.mLayoutSeq = seq;
                     if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
                             + win.mFrame + " mContainingFrame="
@@ -6798,6 +6808,9 @@
         final int dw = mCurDisplayWidth;
         final int dh = mCurDisplayHeight;
 
+        final int innerDw = mPolicy.getNonDecorDisplayWidth(dw);
+        final int innerDh = mPolicy.getNonDecorDisplayHeight(dh);
+
         int i;
 
         if (mFocusMayChange) {
@@ -6897,13 +6910,15 @@
                 boolean tokensAnimating = false;
                 final int NAT = mAppTokens.size();
                 for (i=0; i<NAT; i++) {
-                    if (mAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
+                    if (mAppTokens.get(i).stepAnimationLocked(currentTime,
+                            innerDw, innerDh)) {
                         tokensAnimating = true;
                     }
                 }
                 final int NEAT = mExitingAppTokens.size();
                 for (i=0; i<NEAT; i++) {
-                    if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
+                    if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime,
+                            innerDw, innerDh)) {
                         tokensAnimating = true;
                     }
                 }
@@ -6956,8 +6971,8 @@
 
                         final boolean wasAnimating = w.mAnimating;
 
-                        int animDw = dw;
-                        int animDh = dh;
+                        int animDw = innerDw;
+                        int animDh = innerDh;
 
                         // If the window has moved due to its containing
                         // content frame changing, then we'd like to animate
@@ -7214,6 +7229,7 @@
                         LayoutParams animLp = null;
                         int bestAnimLayer = -1;
                         boolean fullscreenAnim = false;
+                        boolean needBgFiller = false;
 
                         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                                 "New wallpaper target=" + mWallpaperTarget
@@ -7253,9 +7269,10 @@
                                 if (ws != null) {
                                     // If this is a compatibility mode
                                     // window, we will always use its anim.
-                                    if ((ws.mAttrs.flags&FLAG_COMPATIBLE_WINDOW) != 0) {
+                                    if (ws.mNeedsBackgroundFiller) {
                                         animLp = ws.mAttrs;
                                         bestAnimLayer = Integer.MAX_VALUE;
+                                        needBgFiller = true;
                                     } else if (!fullscreenAnim || ws.mLayer > bestAnimLayer) {
                                         animLp = ws.mAttrs;
                                         bestAnimLayer = ws.mLayer;
@@ -7320,7 +7337,8 @@
                             wtoken.reportedVisible = false;
                             wtoken.inPendingTransaction = false;
                             wtoken.animation = null;
-                            setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
+                            setTokenVisibilityLocked(wtoken, animLp, true,
+                                    transit, false, needBgFiller);
                             wtoken.updateReportedVisibilityLocked();
                             wtoken.waitingToShow = false;
                             wtoken.showAllWindowsLocked();
@@ -7332,7 +7350,8 @@
                                     "Now closing app" + wtoken);
                             wtoken.inPendingTransaction = false;
                             wtoken.animation = null;
-                            setTokenVisibilityLocked(wtoken, animLp, false, transit, false);
+                            setTokenVisibilityLocked(wtoken, animLp, false,
+                                    transit, false, needBgFiller);
                             wtoken.updateReportedVisibilityLocked();
                             wtoken.waitingToHide = false;
                             // Force the allDrawn flag, because we want to start
@@ -7835,12 +7854,14 @@
                     }
 
                     boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
-                    if (opaqueDrawn && w.isFullscreen(dw, dh)) {
+                    if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
                         // This window completely covers everything behind it,
                         // so we want to leave all of them as unblurred (for
                         // performance reasons).
                         obscured = true;
-                    } else if (w.needsBackgroundFiller(dw, dh) && (canBeSeen || w.isAnimating())) {
+                    } else if (w.mNeedsBackgroundFiller && w.mHasDrawn
+                            && w.mViewVisibility == View.VISIBLE
+                            && (canBeSeen || w.isAnimating())) {
                         // This window is in compatibility mode, and needs background filler.
                         obscured = true;
                         mBackgroundFillerTarget = w;
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index c05186a..2014e9d 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -72,6 +72,7 @@
     final boolean mIsImWindow;
     final boolean mIsWallpaper;
     final boolean mIsFloatingLayer;
+    final boolean mEnforceSizeCompat;
     int mViewVisibility;
     boolean mPolicyVisibility = true;
     boolean mPolicyVisibilityAfterAnim = true;
@@ -91,6 +92,7 @@
     int mLastLayer;
     boolean mHaveFrame;
     boolean mObscured;
+    boolean mNeedsBackgroundFiller;
     boolean mTurnOnScreen;
 
     int mLayoutSeq = -1;
@@ -154,6 +156,7 @@
 
     // Current transformation being applied.
     boolean mHaveMatrix;
+    float mGlobalScale=1;
     float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
     float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
     float mHScale=1, mVScale=1;
@@ -163,6 +166,7 @@
     // "Real" frame that the application sees.
     final Rect mFrame = new Rect();
     final Rect mLastFrame = new Rect();
+    final Rect mScaledFrame = new Rect();
 
     final Rect mContainingFrame = new Rect();
     final Rect mDisplayFrame = new Rect();
@@ -273,6 +277,7 @@
         mViewVisibility = viewVisibility;
         DeathRecipient deathRecipient = new DeathRecipient();
         mAlpha = a.alpha;
+        mEnforceSizeCompat = (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0;
         if (WindowManagerService.localLOGV) Slog.v(
             WindowManagerService.TAG, "Window " + this + " client=" + c.asBinder()
             + " token=" + token + " (" + mAttrs.token + ")");
@@ -368,7 +373,7 @@
         final Rect display = mDisplayFrame;
         display.set(df);
 
-        if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
+        if (mEnforceSizeCompat) {
             container.intersect(mService.mCompatibleScreenFrame);
             if ((mAttrs.flags & FLAG_LAYOUT_NO_LIMITS) == 0) {
                 display.intersect(mService.mCompatibleScreenFrame);
@@ -416,6 +421,28 @@
         // Now make sure the window fits in the overall display.
         Gravity.applyDisplay(mAttrs.gravity, df, frame);
 
+        int adjRight=0, adjBottom=0;
+
+        if (mEnforceSizeCompat) {
+            // Adjust window offsets by the scaling factor.
+            int xoff = (int)((frame.left-mService.mCompatibleScreenFrame.left)*mGlobalScale)
+                    - (frame.left-mService.mCompatibleScreenFrame.left);
+            int yoff = (int)((frame.top-mService.mCompatibleScreenFrame.top)*mGlobalScale)
+                    - (frame.top-mService.mCompatibleScreenFrame.top);
+            frame.offset(xoff, yoff);
+
+            // We are temporarily going to apply the compatibility scale
+            // to the window so that we can correctly associate it with the
+            // content and visible frame.
+            adjRight = frame.right - frame.left;
+            adjRight = (int)((adjRight)*mGlobalScale + .5f) - adjRight;
+            adjBottom = frame.bottom - frame.top;
+            adjBottom = (int)((adjBottom)*mGlobalScale + .5f) - adjBottom;
+            frame.right += adjRight;
+            frame.bottom += adjBottom;
+        }
+        mScaledFrame.set(frame);
+
         // Make sure the content and visible frames are inside of the
         // final window frame.
         if (content.left < frame.left) content.left = frame.left;
@@ -439,6 +466,22 @@
         visibleInsets.right = frame.right-visible.right;
         visibleInsets.bottom = frame.bottom-visible.bottom;
 
+        if (mEnforceSizeCompat) {
+            // Scale the computed insets back to the window's compatibility
+            // coordinate space, and put frame back to correct size.
+            final float invScale = 1.0f/mGlobalScale;
+            contentInsets.left = (int)(contentInsets.left*invScale);
+            contentInsets.top = (int)(contentInsets.top*invScale);
+            contentInsets.right = (int)(contentInsets.right*invScale);
+            contentInsets.bottom = (int)(contentInsets.bottom*invScale);
+            visibleInsets.left = (int)(visibleInsets.left*invScale);
+            visibleInsets.top = (int)(visibleInsets.top*invScale);
+            visibleInsets.right = (int)(visibleInsets.right*invScale);
+            visibleInsets.bottom = (int)(visibleInsets.bottom*invScale);
+            frame.right -= adjRight;
+            frame.bottom -= adjBottom;
+        }
+
         if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) {
             mService.updateWallpaperOffsetLocked(this, mService.mDisplay.getRealWidth(),
                     mService.mDisplay.getRealHeight(), false);
@@ -819,9 +862,10 @@
                 if (!mLocalAnimating) {
                     if (WindowManagerService.DEBUG_ANIM) Slog.v(
                         WindowManagerService.TAG, "Starting animation in " + this +
-                        " @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() +
+                        " @ " + currentTime + ": ww=" + mScaledFrame.width() +
+                        " wh=" + mScaledFrame.height() +
                         " dw=" + dw + " dh=" + dh + " scale=" + mService.mWindowAnimationScale);
-                    mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh);
+                    mAnimation.initialize(mScaledFrame.width(), mScaledFrame.height(), dw, dh);
                     mAnimation.setStartTime(currentTime);
                     mLocalAnimating = true;
                     mAnimating = true;
@@ -988,6 +1032,14 @@
         return true;
     }
 
+    void prelayout() {
+        if (mEnforceSizeCompat) {
+            mGlobalScale = mService.mCompatibleScreenScale;
+        } else {
+            mGlobalScale = 1;
+        }
+    }
+
     void computeShownFrameLocked() {
         final boolean selfTransformation = mHasLocalTransformation;
         Transformation attachedTransformation =
@@ -1031,6 +1083,7 @@
 
             // Compute the desired transformation.
             tmpMatrix.setTranslate(0, 0);
+            tmpMatrix.postScale(mGlobalScale, mGlobalScale);
             if (selfTransformation) {
                 tmpMatrix.postConcat(mTransformation.getMatrix());
             }
@@ -1105,10 +1158,10 @@
         }
         mShownAlpha = mAlpha;
         mHaveMatrix = false;
-        mDsDx = 1;
+        mDsDx = mGlobalScale;
         mDtDx = 0;
         mDsDy = 0;
-        mDtDy = 1;
+        mDtDy = mGlobalScale;
     }
 
     /**
@@ -1281,12 +1334,14 @@
                 && mService.mPolicy.isScreenOn();
     }
 
-    boolean needsBackgroundFiller(int screenWidth, int screenHeight) {
-        return
+    void evalNeedsBackgroundFiller(int screenWidth, int screenHeight) {
+        mNeedsBackgroundFiller =
              // only if the application is requesting compatible window
-             (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0 &&
+             mEnforceSizeCompat &&
              // only if it's visible
              mHasDrawn && mViewVisibility == View.VISIBLE &&
+             // not needed if the compat window is actually full screen
+             !isFullscreenIgnoringCompat(screenWidth, screenHeight) &&
              // and only if the application fills the compatible screen
              mFrame.left <= mService.mCompatibleScreenFrame.left &&
              mFrame.top <= mService.mCompatibleScreenFrame.top &&
@@ -1295,8 +1350,19 @@
     }
 
     boolean isFullscreen(int screenWidth, int screenHeight) {
-        return mFrame.left <= 0 && mFrame.top <= 0 &&
-                mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
+        if (mEnforceSizeCompat) {
+            return mFrame.left <= mService.mCompatibleScreenFrame.left &&
+                    mFrame.top <= mService.mCompatibleScreenFrame.top &&
+                    mFrame.right >= mService.mCompatibleScreenFrame.right &&
+                    mFrame.bottom >= mService.mCompatibleScreenFrame.bottom;
+        } else {
+            return isFullscreenIgnoringCompat(screenWidth, screenHeight);
+        }
+    }
+
+    boolean isFullscreenIgnoringCompat(int screenWidth, int screenHeight) {
+        return mScaledFrame.left <= 0 && mScaledFrame.top <= 0 &&
+                mScaledFrame.right >= screenWidth && mScaledFrame.bottom >= screenHeight;
     }
 
     void removeLocked() {
@@ -1426,30 +1492,38 @@
         return true;
     }
 
+    private static void applyScaledInsets(Region outRegion, Rect frame, Rect inset, float scale) {
+        if (scale != 1) {
+            outRegion.set(frame.left + (int)(inset.left*scale),
+                    frame.top + (int)(inset.top*scale),
+                    frame.right - (int)(inset.right*scale),
+                    frame.bottom - (int)(inset.bottom*scale));
+        } else {
+            outRegion.set(
+                    frame.left + inset.left, frame.top + inset.top,
+                    frame.right - inset.right, frame.bottom - inset.bottom);
+        }
+    }
+
     public void getTouchableRegion(Region outRegion) {
-        final Rect frame = mFrame;
+        final Rect frame = mScaledFrame;
         switch (mTouchableInsets) {
             default:
             case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
                 outRegion.set(frame);
                 break;
-            case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: {
-                final Rect inset = mGivenContentInsets;
-                outRegion.set(
-                        frame.left + inset.left, frame.top + inset.top,
-                        frame.right - inset.right, frame.bottom - inset.bottom);
+            case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT:
+                applyScaledInsets(outRegion, frame, mGivenContentInsets, mGlobalScale);
                 break;
-            }
-            case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: {
-                final Rect inset = mGivenVisibleInsets;
-                outRegion.set(
-                        frame.left + inset.left, frame.top + inset.top,
-                        frame.right - inset.right, frame.bottom - inset.bottom);
+            case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE:
+                applyScaledInsets(outRegion, frame, mGivenVisibleInsets, mGlobalScale);
                 break;
-            }
             case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION: {
                 final Region givenTouchableRegion = mGivenTouchableRegion;
                 outRegion.set(givenTouchableRegion);
+                if (mGlobalScale != 1) {
+                    outRegion.scale(mGlobalScale);
+                }
                 outRegion.translate(frame.left, frame.top);
                 break;
             }
@@ -1512,7 +1586,8 @@
         }
         pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
                 pw.print(" h="); pw.print(mRequestedHeight);
-                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
+                pw.print(" mLayoutSeq="); pw.print(mLayoutSeq);
+                pw.print(" mNeedsBackgroundFiller="); pw.println(mNeedsBackgroundFiller);
         if (mXOffset != 0 || mYOffset != 0) {
             pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
                     pw.print(" y="); pw.println(mYOffset);
@@ -1533,6 +1608,7 @@
                 pw.println();
         pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
                 pw.print(" last="); mLastFrame.printShortString(pw);
+                pw.print(" scaled="); mScaledFrame.printShortString(pw);
                 pw.println();
         pw.print(prefix); pw.print("mContainingFrame=");
                 mContainingFrame.printShortString(pw);
@@ -1568,8 +1644,9 @@
                     pw.print(" mAlpha="); pw.print(mAlpha);
                     pw.print(" mLastAlpha="); pw.println(mLastAlpha);
         }
-        if (mHaveMatrix) {
-            pw.print(prefix); pw.print("mDsDx="); pw.print(mDsDx);
+        if (mHaveMatrix || mGlobalScale != 1) {
+            pw.print(prefix); pw.print("mGlobalScale="); pw.print(mGlobalScale);
+                    pw.print(" mDsDx="); pw.print(mDsDx);
                     pw.print(" mDtDx="); pw.print(mDtDx);
                     pw.print(" mDsDy="); pw.print(mDsDy);
                     pw.print(" mDtDy="); pw.println(mDtDy);
diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp
index 99f625c..012ce21 100644
--- a/services/jni/com_android_server_InputWindow.cpp
+++ b/services/jni/com_android_server_InputWindow.cpp
@@ -38,6 +38,7 @@
     jfieldID frameTop;
     jfieldID frameRight;
     jfieldID frameBottom;
+    jfieldID scaleFactor;
     jfieldID touchableRegion;
     jfieldID visible;
     jfieldID canReceiveKeys;
@@ -100,6 +101,8 @@
             gInputWindowClassInfo.frameRight);
     outInputWindow->frameBottom = env->GetIntField(inputWindowObj,
             gInputWindowClassInfo.frameBottom);
+    outInputWindow->scaleFactor = env->GetFloatField(inputWindowObj,
+            gInputWindowClassInfo.scaleFactor);
 
     jobject regionObj = env->GetObjectField(inputWindowObj,
             gInputWindowClassInfo.touchableRegion);
@@ -174,6 +177,9 @@
     GET_FIELD_ID(gInputWindowClassInfo.frameBottom, clazz,
             "frameBottom", "I");
 
+    GET_FIELD_ID(gInputWindowClassInfo.scaleFactor, clazz,
+            "scaleFactor", "F");
+
     GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, clazz,
             "touchableRegion", "Landroid/graphics/Region;");
 
diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
index 6192a3c..2a40c57 100644
--- a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
+++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
@@ -62,7 +62,8 @@
                     | ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
                     | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS
                     | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
-                app.getResources().setCompatibilityInfo(new CompatibilityInfo(ai));
+                app.getResources().setCompatibilityInfo(new CompatibilityInfo(ai,
+                        getResources().getConfiguration().screenLayout, false));
             }
         } catch (PackageManager.NameNotFoundException e) {
             throw new RuntimeException("ouch", e);