Merge "wifi-display: mark certification strings as not tranlatable" into klp-dev
diff --git a/src/com/android/settings/HomeSettings.java b/src/com/android/settings/HomeSettings.java
index 6d937fd..bac94d6 100644
--- a/src/com/android/settings/HomeSettings.java
+++ b/src/com/android/settings/HomeSettings.java
@@ -18,12 +18,14 @@
 
 import java.util.ArrayList;
 
+import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.graphics.ColorFilter;
@@ -94,7 +96,7 @@
 
     void uninstallApp(HomeAppPreference pref) {
         // Uninstallation is done by asking the OS to do it
-       Uri packageURI = Uri.parse("package:" + pref.activityName.getPackageName());
+       Uri packageURI = Uri.parse("package:" + pref.uninstallTarget);
        Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
        uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, false);
        int requestCode = REQUESTING_UNINSTALL + (pref.isChecked ? 1 : 0);
@@ -144,9 +146,8 @@
             try {
                 Drawable icon = info.loadIcon(mPm);
                 CharSequence name = info.loadLabel(mPm);
-                boolean isSystem = (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
                 HomeAppPreference pref = new HomeAppPreference(context, activityName, prefIndex,
-                        icon, name, this, isSystem);
+                        icon, name, this, info);
                 mPrefs.add(pref);
                 mPrefGroup.addPreference(pref);
                 pref.setEnabled(true);
@@ -186,14 +187,16 @@
     class HomeAppPreference extends Preference {
         ComponentName activityName;
         int index;
-        boolean isSystem;
         HomeSettings fragment;
         final ColorFilter grayscaleFilter;
         boolean isChecked;
 
+        boolean isSystem;
+        String uninstallTarget;
+
         public HomeAppPreference(Context context, ComponentName activity,
                 int i, Drawable icon, CharSequence title,
-                HomeSettings parent, boolean sys) {
+                HomeSettings parent, ActivityInfo info) {
             super(context);
             setLayoutResource(R.layout.preference_home_app);
             setIcon(icon);
@@ -201,13 +204,41 @@
             activityName = activity;
             fragment = parent;
             index = i;
-            isSystem = sys;
 
             ColorMatrix colorMatrix = new ColorMatrix();
             colorMatrix.setSaturation(0f);
             float[] matrix = colorMatrix.getArray();
             matrix[18] = 0.5f;
             grayscaleFilter = new ColorMatrixColorFilter(colorMatrix);
+
+            determineTargets(info);
+        }
+
+        // Check whether this activity is bundled on the system, with awareness
+        // of the META_HOME_ALTERNATE mechanism.
+        private void determineTargets(ActivityInfo info) {
+            final Bundle meta = info.metaData;
+            if (meta != null) {
+                final String altHomePackage = meta.getString(ActivityManager.META_HOME_ALTERNATE);
+                if (altHomePackage != null) {
+                    try {
+                        final int match = mPm.checkSignatures(info.packageName, altHomePackage);
+                        if (match >= PackageManager.SIGNATURE_MATCH) {
+                            PackageInfo altInfo = mPm.getPackageInfo(altHomePackage, 0);
+                            final int altFlags = altInfo.applicationInfo.flags;
+                            isSystem = (altFlags & ApplicationInfo.FLAG_SYSTEM) != 0;
+                            uninstallTarget = altInfo.packageName;
+                            return;
+                        }
+                    } catch (Exception e) {
+                        // e.g. named alternate package not found during lookup
+                        Log.w(TAG, "Unable to compare/resolve alternate", e);
+                    }
+                }
+            }
+            // No suitable metadata redirect, so use the package's own info
+            isSystem = (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+            uninstallTarget = info.packageName;
         }
 
         @Override
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 6b6e704..5c77a97 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -564,7 +564,9 @@
                 int headerIndex = i + 1;
                 i = insertAccountsHeaders(target, headerIndex);
             } else if (id == R.id.home_settings) {
-                updateHomeSettingHeaders(header);
+                if (!updateHomeSettingHeaders(header)) {
+                    target.remove(i);
+                }
             } else if (id == R.id.user_settings) {
                 if (!UserHandle.MU_ENABLED
                         || !UserManager.supportsMultipleUsers()
@@ -669,11 +671,16 @@
         return ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
     }
 
-    private void updateHomeSettingHeaders(Header header) {
+    private boolean updateHomeSettingHeaders(Header header) {
         final PackageManager pm = getPackageManager();
         final ArrayList<ResolveInfo> homeApps = new ArrayList<ResolveInfo>();
         try {
             ComponentName currentHome = pm.getHomeActivities(homeApps);
+            if (homeApps.size() < 2) {
+                // When there's only one available home app, omit this settings
+                // category entirely at the top level UI.
+                return false;
+            }
             ResolveInfo iconSource = null;
             if (currentHome == null) {
                 // no current default, so find the system home app and use that
@@ -708,6 +715,7 @@
             // Can't look up the home activity; bail on configuring the icon
             Log.w(LOG_TAG, "Problem looking up home activity!", e);
         }
+        return true;
     }
 
     private void getMetaData() {
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index 37c33db..1b3938c 100644
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -66,6 +66,7 @@
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -143,6 +144,8 @@
 
     private PackageMoveObserver mPackageMoveObserver;
 
+    private final HashSet<String> mHomePackages = new HashSet<String>();
+
     private boolean mDisableAfterUninstall;
 
     private boolean mHaveSizes = false;
@@ -320,29 +323,20 @@
 
     private boolean handleDisableable(Button button) {
         boolean disableable = false;
-        try {
-            // Try to prevent the user from bricking their phone
-            // by not allowing disabling of apps signed with the
-            // system cert and any launcher app in the system.
-            PackageInfo sys = mPm.getPackageInfo("android",
-                    PackageManager.GET_SIGNATURES);
-            Intent intent = new Intent(Intent.ACTION_MAIN);
-            intent.addCategory(Intent.CATEGORY_HOME);
-            intent.setPackage(mAppEntry.info.packageName);
-            List<ResolveInfo> homes = mPm.queryIntentActivities(intent, 0);
-            if ((homes != null && homes.size() > 0) || isThisASystemPackage()) {
-                // Disable button for core system applications.
-                button.setText(R.string.disable_text);
-            } else if (mAppEntry.info.enabled) {
-                button.setText(R.string.disable_text);
-                disableable = true;
-            } else {
-                button.setText(R.string.enable_text);
-                disableable = true;
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(TAG, "Unable to get package info", e);
+        // Try to prevent the user from bricking their phone
+        // by not allowing disabling of apps signed with the
+        // system cert and any launcher app in the system.
+        if (mHomePackages.contains(mAppEntry.info.packageName) || isThisASystemPackage()) {
+            // Disable button for core system applications.
+            button.setText(R.string.disable_text);
+        } else if (mAppEntry.info.enabled) {
+            button.setText(R.string.disable_text);
+            disableable = true;
+        } else {
+            button.setText(R.string.enable_text);
+            disableable = true;
         }
+
         return disableable;
     }
 
@@ -638,6 +632,21 @@
         return packageName;
     }
 
+    private boolean signaturesMatch(String pkg1, String pkg2) {
+        if (pkg1 != null && pkg2 != null) {
+            try {
+                final int match = mPm.checkSignatures(pkg1, pkg2);
+                if (match >= PackageManager.SIGNATURE_MATCH) {
+                    return true;
+                }
+            } catch (Exception e) {
+                // e.g. named alternate package not found during lookup;
+                // this is an expected case sometimes
+            }
+        }
+        return false;
+    }
+
     private boolean refreshUi() {
         if (mMoveInProgress) {
             return true;
@@ -652,6 +661,25 @@
             return false; // onCreate must have failed, make sure to exit
         }
 
+        // Get list of "home" apps and trace through any meta-data references
+        List<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
+        mPm.getHomeActivities(homeActivities);
+        mHomePackages.clear();
+        for (int i = 0; i< homeActivities.size(); i++) {
+            ResolveInfo ri = homeActivities.get(i);
+            final String activityPkg = ri.activityInfo.packageName;
+            mHomePackages.add(activityPkg);
+
+            // Also make sure to include anything proxying for the home app
+            final Bundle metadata = ri.activityInfo.metaData;
+            if (metadata != null) {
+                final String metaPkg = metadata.getString(ActivityManager.META_HOME_ALTERNATE);
+                if (signaturesMatch(metaPkg, activityPkg)) {
+                    mHomePackages.add(metaPkg);
+                }
+            }
+        }
+
         // Get list of preferred activities
         List<ComponentName> prefActList = new ArrayList<ComponentName>();
         
@@ -1237,8 +1265,8 @@
             intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppEntry.info.packageName });
             intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid);
             intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mAppEntry.info.uid));
-            getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
-                    Activity.RESULT_CANCELED, null, null);
+            getActivity().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
+                    mCheckKillProcessesReceiver, null, Activity.RESULT_CANCELED, null, null);
         }
     }