diff --git a/res/values/strings.xml b/res/values/strings.xml
index cc2bb44e6bc..cd744c6c180 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2438,6 +2438,8 @@
SD card
Uninstall
+
+ Uninstall for all users
Install
@@ -2509,6 +2511,8 @@
On SD card
Disabled
+
+ Not installed
No apps.
diff --git a/src/com/android/settings/applications/ApplicationsState.java b/src/com/android/settings/applications/ApplicationsState.java
index cca9086016c..2ce6779a18e 100644
--- a/src/com/android/settings/applications/ApplicationsState.java
+++ b/src/com/android/settings/applications/ApplicationsState.java
@@ -163,8 +163,12 @@ public class ApplicationsState {
private final Collator sCollator = Collator.getInstance();
@Override
public int compare(AppEntry object1, AppEntry object2) {
- if (object1.info.enabled != object2.info.enabled) {
- return object1.info.enabled ? -1 : 1;
+ final boolean normal1 = object1.info.enabled
+ && (object1.info.flags&ApplicationInfo.FLAG_INSTALLED) != 0;
+ final boolean normal2 = object2.info.enabled
+ && (object2.info.flags&ApplicationInfo.FLAG_INSTALLED) != 0;
+ if (normal1 != normal2) {
+ return normal1 ? -1 : 1;
}
return sCollator.compare(object1.label, object2.label);
}
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index e056f6a6a36..907bf53df43 100644
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -55,6 +55,8 @@ import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.preference.PreferenceActivity;
import android.text.SpannableString;
import android.text.TextUtils;
@@ -66,6 +68,9 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
@@ -92,12 +97,12 @@ public class InstalledAppDetails extends Fragment
implements View.OnClickListener, CompoundButton.OnCheckedChangeListener,
ApplicationsState.Callbacks {
private static final String TAG="InstalledAppDetails";
- static final boolean SUPPORT_DISABLE_APPS = true;
private static final boolean localLOGV = false;
public static final String ARG_PACKAGE_NAME = "package";
private PackageManager mPm;
+ private UserManager mUserManager;
private IUsbManager mUsbManager;
private AppWidgetManager mAppWidgetManager;
private DevicePolicyManager mDpm;
@@ -167,7 +172,14 @@ public class InstalledAppDetails extends Fragment
private static final int DLG_MOVE_FAILED = DLG_BASE + 6;
private static final int DLG_DISABLE = DLG_BASE + 7;
private static final int DLG_DISABLE_NOTIFICATIONS = DLG_BASE + 8;
-
+
+ // Menu identifiers
+ public static final int UNINSTALL_ALL_USERS_MENU = 1;
+
+ // Result code identifiers
+ public static final int REQUEST_UNINSTALL = 1;
+ public static final int REQUEST_MANAGE_SPACE = 2;
+
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
// If the fragment is gone, don't process any more messages.
@@ -303,30 +315,28 @@ public class InstalledAppDetails extends Fragment
} else {
if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
enabled = false;
- if (SUPPORT_DISABLE_APPS) {
- 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 homes = mPm.queryIntentActivities(intent, 0);
- if ((homes != null && homes.size() > 0) || isThisASystemPackage()) {
- // Disable button for core system applications.
- mUninstallButton.setText(R.string.disable_text);
- } else if (mAppEntry.info.enabled) {
- mUninstallButton.setText(R.string.disable_text);
- enabled = true;
- } else {
- mUninstallButton.setText(R.string.enable_text);
- enabled = true;
- }
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Unable to get package info", e);
+ 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 homes = mPm.queryIntentActivities(intent, 0);
+ if ((homes != null && homes.size() > 0) || isThisASystemPackage()) {
+ // Disable button for core system applications.
+ mUninstallButton.setText(R.string.disable_text);
+ } else if (mAppEntry.info.enabled) {
+ mUninstallButton.setText(R.string.disable_text);
+ enabled = true;
+ } else {
+ mUninstallButton.setText(R.string.enable_text);
+ enabled = true;
}
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Unable to get package info", e);
}
} else if ((mPackageInfo.applicationInfo.flags
& ApplicationInfo.FLAG_INSTALLED) == 0) {
@@ -370,9 +380,12 @@ public class InstalledAppDetails extends Fragment
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ setHasOptionsMenu(true);
+
mState = ApplicationsState.getInstance(getActivity().getApplication());
mSession = mState.newSession(this);
mPm = getActivity().getPackageManager();
+ mUserManager = (UserManager)getActivity().getSystemService(Context.USER_SERVICE);
IBinder b = ServiceManager.getService(Context.USB_SERVICE);
mUsbManager = IUsbManager.Stub.asInterface(b);
mAppWidgetManager = AppWidgetManager.getInstance(getActivity());
@@ -428,6 +441,49 @@ public class InstalledAppDetails extends Fragment
return view;
}
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ menu.add(0, UNINSTALL_ALL_USERS_MENU, 1, R.string.uninstall_all_users_text)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ boolean showIt = true;
+ if (mUpdatedSysApp) {
+ showIt = false;
+ } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ showIt = false;
+ } else if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
+ showIt = false;
+ } else if (UserHandle.myUserId() != 0) {
+ showIt = false;
+ } else if (mUserManager.getUsers().size() < 1) {
+ showIt = false;
+ }
+ menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(showIt);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int menuId = item.getItemId();
+ if (menuId == UNINSTALL_ALL_USERS_MENU) {
+ uninstallPkg(mAppEntry.info.packageName, true);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == REQUEST_UNINSTALL) {
+ if (!refreshUi()) {
+ setIntentAndFinish(true, true);
+ }
+ }
+ }
+
// Utility method to set applicaiton label and icon.
private void setAppLabelAndIcon(PackageInfo pkgInfo) {
View appSnippet = mRootView.findViewById(R.id.app_snippet);
@@ -925,7 +981,7 @@ public class InstalledAppDetails extends Fragment
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Clear user data here
- getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName);
+ getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName, false);
}
})
.setNegativeButton(R.string.dlg_cancel, null)
@@ -1021,12 +1077,12 @@ public class InstalledAppDetails extends Fragment
}
}
- private void uninstallPkg(String packageName) {
+ private void uninstallPkg(String packageName, boolean allUsers) {
// Create new intent to launch Uninstaller activity
Uri packageURI = Uri.parse("package:"+packageName);
- Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
- startActivity(uninstallIntent);
- setIntentAndFinish(true, true);
+ Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
+ uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
+ startActivityForResult(uninstallIntent, REQUEST_UNINSTALL);
}
private void forceStopPackage(String pkgName) {
@@ -1139,7 +1195,7 @@ public class InstalledAppDetails extends Fragment
} catch (NameNotFoundException e) {
}
} else {
- uninstallPkg(packageName);
+ uninstallPkg(packageName, false);
}
}
} else if(v == mActivitiesButton) {
@@ -1160,7 +1216,7 @@ public class InstalledAppDetails extends Fragment
Intent intent = new Intent(Intent.ACTION_DEFAULT);
intent.setClassName(mAppEntry.info.packageName,
mAppEntry.info.manageSpaceActivityName);
- startActivityForResult(intent, -1);
+ startActivityForResult(intent, REQUEST_MANAGE_SPACE);
}
} else {
showDialogInner(DLG_CLEAR_DATA, 0);
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index 0a73b02d0f9..b94d9447c8b 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -774,8 +774,12 @@ public class ManageApplications extends Fragment implements
holder.appIcon.setImageDrawable(entry.icon);
}
holder.updateSizeText(mTab.mInvalidSizeStr, mWhichSize);
- if (InstalledAppDetails.SUPPORT_DISABLE_APPS) {
- holder.disabled.setVisibility(entry.info.enabled ? View.GONE : View.VISIBLE);
+ if ((entry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
+ holder.disabled.setVisibility(View.VISIBLE);
+ holder.disabled.setText(R.string.not_installed);
+ } else if (!entry.info.enabled) {
+ holder.disabled.setVisibility(View.VISIBLE);
+ holder.disabled.setText(R.string.disabled);
} else {
holder.disabled.setVisibility(View.GONE);
}
@@ -997,7 +1001,6 @@ public class ManageApplications extends Fragment implements
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- Log.i(TAG, "onCreateOptionsMenu in " + this + ": " + menu);
mOptionsMenu = menu;
// note: icons removed for now because the cause the new action
// bar UI to be very confusing.