Incorporate home metadata into app details UI

Just as we don't expose disable/uninstall of home applications in this UI,
we now also don't allow disable/uninstall of packages that are proxying
for home apps via the android.app.home.alternate meta-data mechanism.

Also, don't display the 'Home' settings top-level category at all when
there is only a single available home app.

Finally, explicitly note the current user when sending broadcasts,
otherwise API sanity checks get suspicious.

Bug 10749961

Change-Id: I13e11032cb571df19798c4e13c91a572d1ee61a7
This commit is contained in:
Christopher Tate
2013-09-19 14:59:17 -07:00
parent 6741d4db7b
commit 8243c9a722
2 changed files with 62 additions and 26 deletions

View File

@@ -564,7 +564,9 @@ public class Settings extends PreferenceActivity
int headerIndex = i + 1; int headerIndex = i + 1;
i = insertAccountsHeaders(target, headerIndex); i = insertAccountsHeaders(target, headerIndex);
} else if (id == R.id.home_settings) { } else if (id == R.id.home_settings) {
updateHomeSettingHeaders(header); if (!updateHomeSettingHeaders(header)) {
target.remove(i);
}
} else if (id == R.id.user_settings) { } else if (id == R.id.user_settings) {
if (!UserHandle.MU_ENABLED if (!UserHandle.MU_ENABLED
|| !UserManager.supportsMultipleUsers() || !UserManager.supportsMultipleUsers()
@@ -669,11 +671,16 @@ public class Settings extends PreferenceActivity
return ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); return ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
} }
private void updateHomeSettingHeaders(Header header) { private boolean updateHomeSettingHeaders(Header header) {
final PackageManager pm = getPackageManager(); final PackageManager pm = getPackageManager();
final ArrayList<ResolveInfo> homeApps = new ArrayList<ResolveInfo>(); final ArrayList<ResolveInfo> homeApps = new ArrayList<ResolveInfo>();
try { try {
ComponentName currentHome = pm.getHomeActivities(homeApps); 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; ResolveInfo iconSource = null;
if (currentHome == null) { if (currentHome == null) {
// no current default, so find the system home app and use that // no current default, so find the system home app and use that
@@ -708,6 +715,7 @@ public class Settings extends PreferenceActivity
// Can't look up the home activity; bail on configuring the icon // Can't look up the home activity; bail on configuring the icon
Log.w(LOG_TAG, "Problem looking up home activity!", e); Log.w(LOG_TAG, "Problem looking up home activity!", e);
} }
return true;
} }
private void getMetaData() { private void getMetaData() {

View File

@@ -66,6 +66,7 @@ import android.util.Log;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@@ -143,6 +144,8 @@ public class InstalledAppDetails extends Fragment
private PackageMoveObserver mPackageMoveObserver; private PackageMoveObserver mPackageMoveObserver;
private final HashSet<String> mHomePackages = new HashSet<String>();
private boolean mDisableAfterUninstall; private boolean mDisableAfterUninstall;
private boolean mHaveSizes = false; private boolean mHaveSizes = false;
@@ -320,29 +323,20 @@ public class InstalledAppDetails extends Fragment
private boolean handleDisableable(Button button) { private boolean handleDisableable(Button button) {
boolean disableable = false; boolean disableable = false;
try { // Try to prevent the user from bricking their phone
// Try to prevent the user from bricking their phone // by not allowing disabling of apps signed with the
// by not allowing disabling of apps signed with the // system cert and any launcher app in the system.
// system cert and any launcher app in the system. if (mHomePackages.contains(mAppEntry.info.packageName) || isThisASystemPackage()) {
PackageInfo sys = mPm.getPackageInfo("android", // Disable button for core system applications.
PackageManager.GET_SIGNATURES); button.setText(R.string.disable_text);
Intent intent = new Intent(Intent.ACTION_MAIN); } else if (mAppEntry.info.enabled) {
intent.addCategory(Intent.CATEGORY_HOME); button.setText(R.string.disable_text);
intent.setPackage(mAppEntry.info.packageName); disableable = true;
List<ResolveInfo> homes = mPm.queryIntentActivities(intent, 0); } else {
if ((homes != null && homes.size() > 0) || isThisASystemPackage()) { button.setText(R.string.enable_text);
// Disable button for core system applications. disableable = true;
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);
} }
return disableable; return disableable;
} }
@@ -638,6 +632,21 @@ public class InstalledAppDetails extends Fragment
return packageName; 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() { private boolean refreshUi() {
if (mMoveInProgress) { if (mMoveInProgress) {
return true; return true;
@@ -652,6 +661,25 @@ public class InstalledAppDetails extends Fragment
return false; // onCreate must have failed, make sure to exit 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 // Get list of preferred activities
List<ComponentName> prefActList = new ArrayList<ComponentName>(); List<ComponentName> prefActList = new ArrayList<ComponentName>();
@@ -1237,8 +1265,8 @@ public class InstalledAppDetails extends Fragment
intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppEntry.info.packageName }); intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppEntry.info.packageName });
intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid); intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid);
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mAppEntry.info.uid)); intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mAppEntry.info.uid));
getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null, getActivity().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
Activity.RESULT_CANCELED, null, null); mCheckKillProcessesReceiver, null, Activity.RESULT_CANCELED, null, null);
} }
} }