resolved conflicts for merge of 0e59729b to master

Change-Id: I2d3a6bddf66b1df0c101c45ea2fec1cf65caf01b
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 5c8abe4..8a9144c 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -18,6 +18,7 @@
 
 package com.android.commands.am;
 
+import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityController;
 import android.app.IActivityManager;
@@ -794,7 +795,9 @@
         String packageName = nextArgRequired();
         do {
             try {
-                mAm.setPackageScreenCompatMode(packageName, enabled);
+                mAm.setPackageScreenCompatMode(packageName, enabled
+                        ? ActivityManager.COMPAT_MODE_ENABLED
+                        : ActivityManager.COMPAT_MODE_DISABLED);
             } catch (RemoteException e) {
             }
             packageName = nextArg();
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 78a450c..701c7ac 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -204,6 +204,7 @@
     private void runListPackages(boolean showApplicationPackage) {
         int getFlags = 0;
         boolean listDisabled = false, listEnabled = false;
+        boolean listSystem = false, listThirdParty = false;
         try {
             String opt;
             while ((opt=nextOption()) != null) {
@@ -217,6 +218,10 @@
                     listDisabled = true;
                 } else if (opt.equals("-e")) {
                     listEnabled = true;
+                } else if (opt.equals("-s")) {
+                    listSystem = true;
+                } else if (opt.equals("-3")) {
+                    listThirdParty = true;
                 } else if (opt.equals("-u")) {
                     getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
                 } else {
@@ -242,8 +247,12 @@
                 if (filter != null && !info.packageName.contains(filter)) {
                     continue;
                 }
+                final boolean isSystem =
+                        (info.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0;
                 if ((!listDisabled || !info.applicationInfo.enabled) &&
-                        (!listEnabled || info.applicationInfo.enabled)) {
+                        (!listEnabled || info.applicationInfo.enabled) &&
+                        (!listSystem || isSystem) &&
+                        (!listThirdParty || !isSystem)) {
                     System.out.print("package:");
                     if (showApplicationPackage) {
                         System.out.print(info.applicationInfo.sourceDir);
@@ -1061,7 +1070,7 @@
 
     private static void showUsage() {
         System.err.println("usage: pm [list|path|install|uninstall]");
-        System.err.println("       pm list packages [-f] [-d] [-e] [-u] [FILTER]");
+        System.err.println("       pm list packages [-f] [-d] [-e] [-s] [-e] [-u] [FILTER]");
         System.err.println("       pm list permission-groups");
         System.err.println("       pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
         System.err.println("       pm list instrumentation [-f] [TARGET-PACKAGE]");
@@ -1080,8 +1089,10 @@
         System.err.println("The list packages command prints all packages, optionally only");
         System.err.println("those whose package name contains the text in FILTER.  Options:");
         System.err.println("  -f: see their associated file.");
-        System.err.println("  -d: filter to include disbled packages.");
-        System.err.println("  -e: filter to include enabled packages.");
+        System.err.println("  -d: filter to only show disbled packages.");
+        System.err.println("  -e: filter to only show enabled packages.");
+        System.err.println("  -s: filter to only show system packages.");
+        System.err.println("  -3: filter to only show third party packages.");
         System.err.println("  -u: also include uninstalled packages.");
         System.err.println("");
         System.err.println("The list permission-groups command prints all known");
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index fca6868..f48b8ed 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -60,6 +60,82 @@
     }
 
     /**
+     * Screen compatibility mode: the application most always run in
+     * compatibility mode.
+     * @hide
+     */
+    public static final int COMPAT_MODE_ALWAYS = -1;
+
+    /**
+     * Screen compatibility mode: the application can never run in
+     * compatibility mode.
+     * @hide
+     */
+    public static final int COMPAT_MODE_NEVER = -2;
+
+    /**
+     * Screen compatibility mode: unknown.
+     * @hide
+     */
+    public static final int COMPAT_MODE_UNKNOWN = -3;
+
+    /**
+     * Screen compatibility mode: the application currently has compatibility
+     * mode disabled.
+     * @hide
+     */
+    public static final int COMPAT_MODE_DISABLED = 0;
+
+    /**
+     * Screen compatibility mode: the application currently has compatibility
+     * mode enabled.
+     * @hide
+     */
+    public static final int COMPAT_MODE_ENABLED = 1;
+
+    /**
+     * Screen compatibility mode: request to toggle the application's
+     * compatibility mode.
+     * @hide
+     */
+    public static final int COMPAT_MODE_TOGGLE = 2;
+
+    /** @hide */
+    public int getFrontActivityScreenCompatMode() {
+        try {
+            return ActivityManagerNative.getDefault().getFrontActivityScreenCompatMode();
+        } catch (RemoteException e) {
+            // System dead, we will be dead too soon!
+            return 0;
+        }
+    }
+
+    public void setFrontActivityScreenCompatMode(int mode) {
+        try {
+            ActivityManagerNative.getDefault().setFrontActivityScreenCompatMode(mode);
+        } catch (RemoteException e) {
+            // System dead, we will be dead too soon!
+        }
+    }
+
+    public int getPackageScreenCompatMode(String packageName) {
+        try {
+            return ActivityManagerNative.getDefault().getPackageScreenCompatMode(packageName);
+        } catch (RemoteException e) {
+            // System dead, we will be dead too soon!
+            return 0;
+        }
+    }
+
+    public void setPackageScreenCompatMode(String packageName, int mode) {
+        try {
+            ActivityManagerNative.getDefault().setPackageScreenCompatMode(packageName, mode);
+        } catch (RemoteException e) {
+            // System dead, we will be dead too soon!
+        }
+    }
+
+    /**
      * Return the approximate per-application memory class of the current
      * device.  This gives you an idea of how hard a memory limit you should
      * impose on your application to let the overall system work best.  The
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 5ffaee7..f2c97964 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1397,12 +1397,41 @@
             return true;
         }
 
+        case GET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION:
+        {
+            data.enforceInterface(IActivityManager.descriptor);
+            int mode = getFrontActivityScreenCompatMode();
+            reply.writeNoException();
+            reply.writeInt(mode);
+            return true;
+        }
+
+        case SET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION:
+        {
+            data.enforceInterface(IActivityManager.descriptor);
+            int mode = data.readInt();
+            setFrontActivityScreenCompatMode(mode);
+            reply.writeNoException();
+            reply.writeInt(mode);
+            return true;
+        }
+
+        case GET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION:
+        {
+            data.enforceInterface(IActivityManager.descriptor);
+            String pkg = data.readString();
+            int mode = getPackageScreenCompatMode(pkg);
+            reply.writeNoException();
+            reply.writeInt(mode);
+            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);
+            int mode = data.readInt();
+            setPackageScreenCompatMode(pkg, mode);
             reply.writeNoException();
             return true;
         }
@@ -3182,13 +3211,48 @@
         return result;
     }
 
-    public void setPackageScreenCompatMode(String packageName, boolean compatEnabled)
+    public int getFrontActivityScreenCompatMode() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int mode = reply.readInt();
+        reply.recycle();
+        data.recycle();
+        return mode;
+    }
+
+    public void setFrontActivityScreenCompatMode(int mode) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(mode);
+        mRemote.transact(SET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION, data, reply, 0);
+        reply.readException();
+        reply.recycle();
+        data.recycle();
+    }
+
+    public int getPackageScreenCompatMode(String packageName) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int mode = reply.readInt();
+        reply.recycle();
+        data.recycle();
+        return mode;
+    }
+
+    public void setPackageScreenCompatMode(String packageName, int mode)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeString(packageName);
-        data.writeInt(compatEnabled ? 1 : 0);
+        data.writeInt(mode);
         mRemote.transact(SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION, data, reply, 0);
         reply.readException();
         reply.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 994a924..54c3422 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -342,7 +342,10 @@
     public int startActivitiesInPackage(int uid,
             Intent[] intents, String[] resolvedTypes, IBinder resultTo) throws RemoteException;
 
-    public void setPackageScreenCompatMode(String packageName, boolean compatEnabled)
+    public int getFrontActivityScreenCompatMode() throws RemoteException;
+    public void setFrontActivityScreenCompatMode(int mode) throws RemoteException;
+    public int getPackageScreenCompatMode(String packageName) throws RemoteException;
+    public void setPackageScreenCompatMode(String packageName, int mode)
             throws RemoteException;
     
     // Multi-user APIs
@@ -567,8 +570,11 @@
     int START_ACTIVITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+120;
     int START_ACTIVITIES_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+121;
     int ACTIVITY_SLEPT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+122;
-    int SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+123;
-    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;
+    int GET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+123;
+    int SET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+124;
+    int GET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+125;
+    int SET_PACKAGE_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+126;
+    int SWITCH_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+127;
+    int REMOVE_SUB_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+128;
+    int REMOVE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+129;
 }
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index ab9bfce..8bcb005 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -81,9 +81,19 @@
     private static final int XLARGE_SCREENS = 32;
     
     /**
+     * Application must always run in compatibility mode?
+     */
+    private static final int ALWAYS_COMPAT = 64;
+
+    /**
+     * Application never should run in compatibility mode?
+     */
+    private static final int NEVER_COMPAT = 128;
+
+    /**
      * Set if the application needs to run in screen size compatibility mode.
      */
-    private static final int NEEDS_SCREEN_COMPAT = 128;
+    private static final int NEEDS_SCREEN_COMPAT = 256;
 
     /**
      * The effective screen density we have selected for this application.
@@ -131,11 +141,17 @@
                 if ((compatFlags&XLARGE_SCREENS) != 0) {
                     supportsScreen = true;
                 }
+                if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
+                    compatFlags |= NEVER_COMPAT;
+                }
                 break;
             case Configuration.SCREENLAYOUT_SIZE_LARGE:
                 if ((compatFlags&LARGE_SCREENS) != 0) {
                     supportsScreen = true;
                 }
+                if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
+                    compatFlags |= NEVER_COMPAT;
+                }
                 break;
         }
 
@@ -143,6 +159,10 @@
             if ((compatFlags&EXPANDABLE) != 0) {
                 supportsScreen = true;
             }
+            if ((compatFlags&EXPANDABLE) == 0 &&
+                    (appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) == 0) {
+                compatFlags |= ALWAYS_COMPAT;
+            }
         }
 
         if (supportsScreen) {
@@ -192,6 +212,14 @@
         return (mCompatibilityFlags&NEEDS_SCREEN_COMPAT) == 0;
     }
     
+    public boolean neverSupportsScreen() {
+        return (mCompatibilityFlags&NEVER_COMPAT) != 0;
+    }
+
+    public boolean alwaysSupportsScreen() {
+        return (mCompatibilityFlags&ALWAYS_COMPAT) != 0;
+    }
+
     @Override
     public String toString() {
         return "CompatibilityInfo{scale=" + applicationScale + "}";
diff --git a/packages/SystemUI/res/drawable-mdpi/hd_off.png b/packages/SystemUI/res/drawable-mdpi/hd_off.png
new file mode 100644
index 0000000..ad09eef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/hd_off.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/hd_on.png b/packages/SystemUI/res/drawable-mdpi/hd_on.png
new file mode 100644
index 0000000..1471c13
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/hd_on.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/hd.xml b/packages/SystemUI/res/drawable/hd.xml
new file mode 100644
index 0000000..73867a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/hd.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_checked="false"
+          android:drawable="@drawable/hd_off" />
+    <item android:drawable="@drawable/hd_on" />
+</selector>
diff --git a/packages/SystemUI/res/layout-large/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-large/status_bar_recent_panel.xml
index 42940be..f019e2d 100644
--- a/packages/SystemUI/res/layout-large/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-large/status_bar_recent_panel.xml
@@ -24,11 +24,23 @@
     android:layout_height="match_parent"
     android:layout_width="wrap_content">
 
+    <CheckBox android:id="@+id/recents_compat_mode"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentRight="true"
+        android:layout_marginLeft="16dp"
+        android:layout_marginBottom="@*android:dimen/status_bar_height"
+        android:background="@drawable/hd"
+        android:button="@null"
+    />
+
     <FrameLayout
         android:id="@+id/recents_bg_protect"
         android:background="@drawable/recents_bg_protect_tile"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
+        android:layout_toLeftOf="@id/recents_compat_mode"
         android:layout_alignParentBottom="true"
         android:paddingBottom="@*android:dimen/status_bar_height"
         android:clipToPadding="false">
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
index cfb4975..d0e6551 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
@@ -50,6 +50,7 @@
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.BaseAdapter;
+import android.widget.CheckBox;
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.RelativeLayout;
@@ -69,6 +70,7 @@
     private View mRecentsScrim;
     private View mRecentsGlowView;
     private ListView mRecentsContainer;
+    private CheckBox mCompatMode;
     private Bitmap mGlowBitmap;
     private boolean mShowing;
     private Choreographer mChoreo;
@@ -356,6 +358,15 @@
         mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 
         mRecentsContainer = (ListView) findViewById(R.id.recents_container);
+        mCompatMode = (CheckBox) findViewById(R.id.recents_compat_mode);
+        mCompatMode.setOnClickListener(new OnClickListener() {
+            public void onClick(View v) {
+                final ActivityManager am = (ActivityManager)
+                        mContext.getSystemService(Context.ACTIVITY_SERVICE);
+                am.setFrontActivityScreenCompatMode(ActivityManager.COMPAT_MODE_TOGGLE);
+                hide(true);
+            }
+        });
         View footer = inflater.inflate(R.layout.status_bar_recent_panel_footer,
                 mRecentsContainer, false);
         mRecentsContainer.setScrollbarFadingEnabled(true);
@@ -493,12 +504,32 @@
         return desc;
     }
 
+    private void updateShownCompatMode() {
+        final ActivityManager am = (ActivityManager)
+                mContext.getSystemService(Context.ACTIVITY_SERVICE);
+        int mode = am.getFrontActivityScreenCompatMode();
+        switch (mode) {
+            case ActivityManager.COMPAT_MODE_DISABLED:
+                mCompatMode.setVisibility(View.VISIBLE);
+                mCompatMode.setChecked(true);
+                break;
+            case ActivityManager.COMPAT_MODE_ENABLED:
+                mCompatMode.setVisibility(View.VISIBLE);
+                mCompatMode.setChecked(false);
+                break;
+            default:
+                mCompatMode.setVisibility(View.GONE);
+                break;
+        }
+    }
+
     private void refreshApplicationList() {
         mActivityDescriptions = getRecentTasks();
         mListAdapter.notifyDataSetInvalidated();
         if (mActivityDescriptions.size() > 0) {
             mLastVisibleItem = mActivityDescriptions.size() - 1; // scroll to bottom after reloading
             updateUiElements(getResources().getConfiguration());
+            updateShownCompatMode();
         } else {
             // Immediately hide this panel
             hide(false);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 586bb6b..f6ae523 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -548,7 +548,7 @@
      * 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>();
+    final CompatModePackages mCompatModePackages;
 
     /**
      * Set of PendingResultRecord objects that are currently active.
@@ -1468,6 +1468,8 @@
         mConfiguration.locale = Locale.getDefault();
         mProcessStats.init();
         
+        mCompatModePackages = new CompatModePackages(this, systemDir);
+
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
 
@@ -2082,70 +2084,30 @@
     }
     
     CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
-        return new CompatibilityInfo(ai, mConfiguration.screenLayout,
-                mScreenCompatPackages.contains(ai.packageName));
+        return mCompatModePackages.compatibilityInfoForPackageLocked(ai);
     }
 
-    public void setPackageScreenCompatMode(String packageName, boolean compatEnabled) {
+    public int getFrontActivityScreenCompatMode() {
         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);
+            return mCompatModePackages.getFrontActivityScreenCompatModeLocked();
+        }
+    }
 
-                // 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) {
-                    }
-                }
+    public void setFrontActivityScreenCompatMode(int mode) {
+        synchronized (this) {
+            mCompatModePackages.setFrontActivityScreenCompatModeLocked(mode);
+        }
+    }
 
-                // 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;
-                    }
-                }
+    public int getPackageScreenCompatMode(String packageName) {
+        synchronized (this) {
+            return mCompatModePackages.getPackageScreenCompatModeLocked(packageName);
+        }
+    }
 
-                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);
-                }
-            }
+    public void setPackageScreenCompatMode(String packageName, int mode) {
+        synchronized (this) {
+            mCompatModePackages.setPackageScreenCompatModeLocked(packageName, mode);
         }
     }
 
@@ -7945,9 +7907,9 @@
         pw.println("  mConfiguration: " + mConfiguration);
         if (dumpAll) {
             pw.println("  mConfigWillChange: " + mMainStack.mConfigWillChange);
-            if (mScreenCompatPackages.size() > 0) {
+            if (mCompatModePackages.getPackages().size() > 0) {
                 pw.print("  mScreenCompatPackages=");
-                pw.println(mScreenCompatPackages);
+                pw.println(mCompatModePackages.getPackages());
             }
         }
         pw.println("  mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
@@ -11036,10 +10998,10 @@
         // Handle special intents: if this broadcast is from the package
         // manager about a package being removed, we need to remove all of
         // its activities from the history stack.
-        final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
+        final boolean uidRemoved = Intent.ACTION_UID_REMOVED.equals(
                 intent.getAction());
-        if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
-                || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
+        if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
+                || Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
                 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())
                 || uidRemoved) {
             if (checkComponentPermission(
@@ -11076,7 +11038,7 @@
                                 forceStopPackageLocked(ssp,
                                         intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true);
                             }
-                            if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+                            if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
                                 sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
                                         new String[] {ssp});
                             }
@@ -11092,6 +11054,18 @@
                 Slog.w(TAG, msg);
                 throw new SecurityException(msg);
             }
+
+        // Special case for adding a package: by default turn on compatibility
+        // mode.
+        } else if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
+            if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                Uri data = intent.getData();
+                String ssp;
+                if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
+                    mCompatModePackages.setPackageScreenCompatModeLocked(ssp,
+                            ActivityManager.COMPAT_MODE_ENABLED);
+                }
+            }
         }
 
         /*
@@ -11250,9 +11224,9 @@
             // broadcast or such for apps, but we'd like to deliberately make
             // this decision.
             String skipPackages[] = null;
-            if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
-                    || intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
-                    || intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
+            if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
+                    || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
+                    || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
                 Uri data = intent.getData();
                 if (data != null) {
                     String pkgName = data.getSchemeSpecificPart();
@@ -11260,7 +11234,7 @@
                         skipPackages = new String[] { pkgName };
                     }
                 }
-            } else if (intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
+            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
                 skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
             }
             if (skipPackages != null && (skipPackages.length > 0)) {
diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java
new file mode 100644
index 0000000..1faf8da
--- /dev/null
+++ b/services/java/com/android/server/am/CompatModePackages.java
@@ -0,0 +1,295 @@
+package com.android.server.am;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import com.android.internal.os.AtomicFile;
+import com.android.internal.util.FastXmlSerializer;
+
+import android.app.ActivityManager;
+import android.app.AppGlobals;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.res.CompatibilityInfo;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.util.Xml;
+
+public class CompatModePackages {
+    private final String TAG = ActivityManagerService.TAG;
+    private final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
+
+    private final ActivityManagerService mService;
+    private final AtomicFile mFile;
+
+    private final HashSet<String> mPackages = new HashSet<String>();
+
+    private static final int MSG_WRITE = 1;
+
+    private final Handler mHandler = new Handler() {
+        @Override public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_WRITE:
+                    saveCompatModes();
+                    break;
+                default:
+                    super.handleMessage(msg);
+                    break;
+            }
+        }
+    };
+
+    public CompatModePackages(ActivityManagerService service, File systemDir) {
+        mService = service;
+        mFile = new AtomicFile(new File(systemDir, "packages-compat.xml"));
+
+        FileInputStream fis = null;
+        try {
+            fis = mFile.openRead();
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(fis, null);
+            int eventType = parser.getEventType();
+            while (eventType != XmlPullParser.START_TAG) {
+                eventType = parser.next();
+            }
+            String tagName = parser.getName();
+            if ("compat-packages".equals(tagName)) {
+                eventType = parser.next();
+                do {
+                    if (eventType == XmlPullParser.START_TAG) {
+                        tagName = parser.getName();
+                        if (parser.getDepth() == 2) {
+                            if ("pkg".equals(tagName)) {
+                                String pkg = parser.getAttributeValue(null, "name");
+                                if (pkg != null) {
+                                    mPackages.add(pkg);
+                                }
+                            }
+                        }
+                    }
+                    eventType = parser.next();
+                } while (eventType != XmlPullParser.END_DOCUMENT);
+            }
+        } catch (XmlPullParserException e) {
+            Slog.w(TAG, "Error reading compat-packages", e);
+        } catch (java.io.IOException e) {
+            if (fis != null) Slog.w(TAG, "Error reading compat-packages", e);
+        } finally {
+            if (fis != null) {
+                try {
+                    fis.close();
+                } catch (java.io.IOException e1) {
+                }
+            }
+        }
+    }
+
+    public HashSet<String> getPackages() {
+        return mPackages;
+    }
+
+    public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
+        return new CompatibilityInfo(ai, mService.mConfiguration.screenLayout,
+                mPackages.contains(ai.packageName));
+    }
+
+    private int computeCompatModeLocked(ApplicationInfo ai) {
+        boolean enabled = mPackages.contains(ai.packageName);
+        CompatibilityInfo info = new CompatibilityInfo(ai,
+                mService.mConfiguration.screenLayout, enabled);
+        if (info.alwaysSupportsScreen()) {
+            return ActivityManager.COMPAT_MODE_NEVER;
+        }
+        if (info.neverSupportsScreen()) {
+            return ActivityManager.COMPAT_MODE_ALWAYS;
+        }
+        return enabled ? ActivityManager.COMPAT_MODE_ENABLED
+                : ActivityManager.COMPAT_MODE_DISABLED;
+    }
+
+    public int getFrontActivityScreenCompatModeLocked() {
+        ActivityRecord r = mService.mMainStack.topRunningActivityLocked(null);
+        if (r == null) {
+            return ActivityManager.COMPAT_MODE_UNKNOWN;
+        }
+        return computeCompatModeLocked(r.info.applicationInfo);
+    }
+
+    public void setFrontActivityScreenCompatModeLocked(int mode) {
+        ActivityRecord r = mService.mMainStack.topRunningActivityLocked(null);
+        if (r == null) {
+            Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity");
+            return;
+        }
+        setPackageScreenCompatModeLocked(r.info.applicationInfo, mode);
+    }
+
+    public int getPackageScreenCompatModeLocked(String packageName) {
+        ApplicationInfo ai = null;
+        try {
+            ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0);
+        } catch (RemoteException e) {
+        }
+        if (ai == null) {
+            return ActivityManager.COMPAT_MODE_UNKNOWN;
+        }
+        return computeCompatModeLocked(ai);
+    }
+
+    public void setPackageScreenCompatModeLocked(String packageName, int mode) {
+        ApplicationInfo ai = null;
+        try {
+            ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0);
+        } catch (RemoteException e) {
+        }
+        if (ai == null) {
+            Slog.w(TAG, "setPackageScreenCompatMode failed: unknown package " + packageName);
+            return;
+        }
+        setPackageScreenCompatModeLocked(ai, mode);
+    }
+
+    private void setPackageScreenCompatModeLocked(ApplicationInfo ai, int mode) {
+        final String packageName = ai.packageName;
+
+        boolean changed = false;
+        boolean enable;
+        switch (mode) {
+            case ActivityManager.COMPAT_MODE_DISABLED:
+                enable = false;
+                break;
+            case ActivityManager.COMPAT_MODE_ENABLED:
+                enable = true;
+                break;
+            case ActivityManager.COMPAT_MODE_TOGGLE:
+                enable = !mPackages.contains(packageName);
+                break;
+            default:
+                Slog.w(TAG, "Unknown screen compat mode req #" + mode + "; ignoring");
+                return;
+        }
+        if (enable) {
+            if (!mPackages.contains(packageName)) {
+                changed = true;
+                mPackages.add(packageName);
+            }
+        } else {
+            if (mPackages.contains(packageName)) {
+                changed = true;
+                mPackages.remove(packageName);
+            }
+        }
+        if (changed) {
+            CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai);
+            if (ci.alwaysSupportsScreen()) {
+                Slog.w(TAG, "Ignoring compat mode change of " + packageName
+                        + "; compatibility never needed");
+                return;
+            }
+            if (ci.neverSupportsScreen()) {
+                Slog.w(TAG, "Ignoring compat mode change of " + packageName
+                        + "; compatibility always needed");
+                return;
+            }
+
+            mHandler.removeMessages(MSG_WRITE);
+            Message msg = mHandler.obtainMessage(MSG_WRITE);
+            mHandler.sendMessageDelayed(msg, 10000);
+
+            // Tell all processes that loaded this package about the change.
+            for (int i=mService.mLruProcesses.size()-1; i>=0; i--) {
+                ProcessRecord app = mService.mLruProcesses.get(i);
+                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=mService.mMainStack.mHistory.size()-1; i>=0; i--) {
+                ActivityRecord a = (ActivityRecord)mService.mMainStack.mHistory.get(i);
+                if (a.info.packageName.equals(packageName)) {
+                    a.forceNewConfig = true;
+                }
+            }
+
+            ActivityRecord starting = mService.mMainStack.topRunningActivityLocked(null);
+            if (starting != null) {
+                mService.mMainStack.ensureActivityConfigurationLocked(starting, 0);
+                // And we need to make sure at this point that all other activities
+                // are made visible with the correct configuration.
+                mService.mMainStack.ensureActivitiesVisibleLocked(starting, 0);
+            }
+        }
+    }
+
+    void saveCompatModes() {
+        HashSet<String> pkgs;
+        synchronized (mService) {
+            pkgs = new HashSet<String>(mPackages);
+        }
+
+        FileOutputStream fos = null;
+
+        try {
+            fos = mFile.startWrite();
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(fos, "utf-8");
+            out.startDocument(null, true);
+            out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+            out.startTag(null, "compat-packages");
+
+            final IPackageManager pm = AppGlobals.getPackageManager();
+            final int screenLayout = mService.mConfiguration.screenLayout;
+            final Iterator<String> it = pkgs.iterator();
+            while (it.hasNext()) {
+                String pkg = it.next();
+                ApplicationInfo ai = null;
+                try {
+                    ai = pm.getApplicationInfo(pkg, 0);
+                } catch (RemoteException e) {
+                }
+                if (ai == null) {
+                    continue;
+                }
+                CompatibilityInfo info = new CompatibilityInfo(ai, screenLayout, false);
+                if (info.alwaysSupportsScreen()) {
+                    continue;
+                }
+                if (info.neverSupportsScreen()) {
+                    continue;
+                }
+                out.startTag(null, "pkg");
+                out.attribute(null, "name", pkg);
+                out.endTag(null, "pkg");
+            }
+
+            out.endTag(null, "compat-packages");
+            out.endDocument();
+
+            mFile.finishWrite(fos);
+        } catch (java.io.IOException e1) {
+            Slog.w(TAG, "Error writing compat packages", e1);
+            if (fos != null) {
+                mFile.failWrite(fos);
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 16b55c3..2720bf8 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -142,18 +142,11 @@
     Settings() {
         File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
-        // TODO(oam): This secure dir creation needs to be moved somewhere else (later)
-        File systemSecureDir = new File(dataDir, "secure/system");
         systemDir.mkdirs();
-        systemSecureDir.mkdirs();
         FileUtils.setPermissions(systemDir.toString(),
                 FileUtils.S_IRWXU|FileUtils.S_IRWXG
                 |FileUtils.S_IROTH|FileUtils.S_IXOTH,
                 -1, -1);
-        FileUtils.setPermissions(systemSecureDir.toString(),
-                FileUtils.S_IRWXU|FileUtils.S_IRWXG
-                |FileUtils.S_IROTH|FileUtils.S_IXOTH,
-                -1, -1);
         mSettingsFilename = new File(systemDir, "packages.xml");
         mBackupSettingsFilename = new File(systemDir, "packages-backup.xml");
         mPackageListFilename = new File(systemDir, "packages.list");