Add app details menu item to uninstall an app for all users.
Also some fixes: uninstalled apps are now marked as such in the all apps lists, and sorted to the bottom like disabled apps. We don't immediately close the installed app details screen when launching the uninstall UI. Change-Id: Id22b749c20fc2441733c604d1de8889269217c5c
This commit is contained in:
@@ -2438,6 +2438,8 @@
|
|||||||
<string name="external_data_size_label" product="default">SD card</string>
|
<string name="external_data_size_label" product="default">SD card</string>
|
||||||
<!-- Manage applications, individual application info screen, button label under Storage heading. Button to remove the application from the system. -->
|
<!-- Manage applications, individual application info screen, button label under Storage heading. Button to remove the application from the system. -->
|
||||||
<string name="uninstall_text">Uninstall</string>
|
<string name="uninstall_text">Uninstall</string>
|
||||||
|
<!-- Manage applications, individual application info screen, menu item to uninstall an application for all users. -->
|
||||||
|
<string name="uninstall_all_users_text">Uninstall for all users</string>
|
||||||
<!-- [CHAR LIMIT=NONE] Manage applications, individual application info screen, button label under Storage heading. Button to install an application for the user. -->
|
<!-- [CHAR LIMIT=NONE] Manage applications, individual application info screen, button label under Storage heading. Button to install an application for the user. -->
|
||||||
<string name="install_text">Install</string>
|
<string name="install_text">Install</string>
|
||||||
<!-- [CHAR LIMIT=25] Manage applications, individual application info screen, button label under Storage heading. Button to disable an existing application. -->
|
<!-- [CHAR LIMIT=25] Manage applications, individual application info screen, button label under Storage heading. Button to disable an existing application. -->
|
||||||
@@ -2509,6 +2511,8 @@
|
|||||||
<string name="filter_apps_onsdcard" product="default">On SD card</string>
|
<string name="filter_apps_onsdcard" product="default">On SD card</string>
|
||||||
<!-- [CHAR LIMIT=25] Manage applications, text telling using an application is disabled. -->
|
<!-- [CHAR LIMIT=25] Manage applications, text telling using an application is disabled. -->
|
||||||
<string name="disabled">Disabled</string>
|
<string name="disabled">Disabled</string>
|
||||||
|
<!-- [CHAR LIMIT=25] Manage applications, text telling using an application is not installed. -->
|
||||||
|
<string name="not_installed">Not installed</string>
|
||||||
<!-- [CHAR LIMIT=25] Text shown when there are no applications to display. -->
|
<!-- [CHAR LIMIT=25] Text shown when there are no applications to display. -->
|
||||||
<string name="no_applications">No apps.</string>
|
<string name="no_applications">No apps.</string>
|
||||||
<!-- [CHAR LIMIT=15] Manage applications, label for chart showing internal storage use. -->
|
<!-- [CHAR LIMIT=15] Manage applications, label for chart showing internal storage use. -->
|
||||||
|
@@ -163,8 +163,12 @@ public class ApplicationsState {
|
|||||||
private final Collator sCollator = Collator.getInstance();
|
private final Collator sCollator = Collator.getInstance();
|
||||||
@Override
|
@Override
|
||||||
public int compare(AppEntry object1, AppEntry object2) {
|
public int compare(AppEntry object1, AppEntry object2) {
|
||||||
if (object1.info.enabled != object2.info.enabled) {
|
final boolean normal1 = object1.info.enabled
|
||||||
return object1.info.enabled ? -1 : 1;
|
&& (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);
|
return sCollator.compare(object1.label, object2.label);
|
||||||
}
|
}
|
||||||
|
@@ -55,6 +55,8 @@ import android.os.IBinder;
|
|||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.os.UserManager;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -66,6 +68,9 @@ import java.lang.ref.WeakReference;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
@@ -92,12 +97,12 @@ public class InstalledAppDetails extends Fragment
|
|||||||
implements View.OnClickListener, CompoundButton.OnCheckedChangeListener,
|
implements View.OnClickListener, CompoundButton.OnCheckedChangeListener,
|
||||||
ApplicationsState.Callbacks {
|
ApplicationsState.Callbacks {
|
||||||
private static final String TAG="InstalledAppDetails";
|
private static final String TAG="InstalledAppDetails";
|
||||||
static final boolean SUPPORT_DISABLE_APPS = true;
|
|
||||||
private static final boolean localLOGV = false;
|
private static final boolean localLOGV = false;
|
||||||
|
|
||||||
public static final String ARG_PACKAGE_NAME = "package";
|
public static final String ARG_PACKAGE_NAME = "package";
|
||||||
|
|
||||||
private PackageManager mPm;
|
private PackageManager mPm;
|
||||||
|
private UserManager mUserManager;
|
||||||
private IUsbManager mUsbManager;
|
private IUsbManager mUsbManager;
|
||||||
private AppWidgetManager mAppWidgetManager;
|
private AppWidgetManager mAppWidgetManager;
|
||||||
private DevicePolicyManager mDpm;
|
private DevicePolicyManager mDpm;
|
||||||
@@ -168,6 +173,13 @@ public class InstalledAppDetails extends Fragment
|
|||||||
private static final int DLG_DISABLE = DLG_BASE + 7;
|
private static final int DLG_DISABLE = DLG_BASE + 7;
|
||||||
private static final int DLG_DISABLE_NOTIFICATIONS = DLG_BASE + 8;
|
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() {
|
private Handler mHandler = new Handler() {
|
||||||
public void handleMessage(Message msg) {
|
public void handleMessage(Message msg) {
|
||||||
// If the fragment is gone, don't process any more messages.
|
// If the fragment is gone, don't process any more messages.
|
||||||
@@ -303,7 +315,6 @@ public class InstalledAppDetails extends Fragment
|
|||||||
} else {
|
} else {
|
||||||
if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
|
if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
|
||||||
enabled = false;
|
enabled = false;
|
||||||
if (SUPPORT_DISABLE_APPS) {
|
|
||||||
try {
|
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
|
||||||
@@ -327,7 +338,6 @@ public class InstalledAppDetails extends Fragment
|
|||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
Log.w(TAG, "Unable to get package info", e);
|
Log.w(TAG, "Unable to get package info", e);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if ((mPackageInfo.applicationInfo.flags
|
} else if ((mPackageInfo.applicationInfo.flags
|
||||||
& ApplicationInfo.FLAG_INSTALLED) == 0) {
|
& ApplicationInfo.FLAG_INSTALLED) == 0) {
|
||||||
mUninstallButton.setText(R.string.install_text);
|
mUninstallButton.setText(R.string.install_text);
|
||||||
@@ -370,9 +380,12 @@ public class InstalledAppDetails extends Fragment
|
|||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
|
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
|
||||||
mState = ApplicationsState.getInstance(getActivity().getApplication());
|
mState = ApplicationsState.getInstance(getActivity().getApplication());
|
||||||
mSession = mState.newSession(this);
|
mSession = mState.newSession(this);
|
||||||
mPm = getActivity().getPackageManager();
|
mPm = getActivity().getPackageManager();
|
||||||
|
mUserManager = (UserManager)getActivity().getSystemService(Context.USER_SERVICE);
|
||||||
IBinder b = ServiceManager.getService(Context.USB_SERVICE);
|
IBinder b = ServiceManager.getService(Context.USB_SERVICE);
|
||||||
mUsbManager = IUsbManager.Stub.asInterface(b);
|
mUsbManager = IUsbManager.Stub.asInterface(b);
|
||||||
mAppWidgetManager = AppWidgetManager.getInstance(getActivity());
|
mAppWidgetManager = AppWidgetManager.getInstance(getActivity());
|
||||||
@@ -428,6 +441,49 @@ public class InstalledAppDetails extends Fragment
|
|||||||
return view;
|
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.
|
// Utility method to set applicaiton label and icon.
|
||||||
private void setAppLabelAndIcon(PackageInfo pkgInfo) {
|
private void setAppLabelAndIcon(PackageInfo pkgInfo) {
|
||||||
View appSnippet = mRootView.findViewById(R.id.app_snippet);
|
View appSnippet = mRootView.findViewById(R.id.app_snippet);
|
||||||
@@ -925,7 +981,7 @@ public class InstalledAppDetails extends Fragment
|
|||||||
new DialogInterface.OnClickListener() {
|
new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
// Clear user data here
|
// Clear user data here
|
||||||
getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName);
|
getOwner().uninstallPkg(getOwner().mAppEntry.info.packageName, false);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.setNegativeButton(R.string.dlg_cancel, null)
|
.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
|
// Create new intent to launch Uninstaller activity
|
||||||
Uri packageURI = Uri.parse("package:"+packageName);
|
Uri packageURI = Uri.parse("package:"+packageName);
|
||||||
Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
|
Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
|
||||||
startActivity(uninstallIntent);
|
uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
|
||||||
setIntentAndFinish(true, true);
|
startActivityForResult(uninstallIntent, REQUEST_UNINSTALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void forceStopPackage(String pkgName) {
|
private void forceStopPackage(String pkgName) {
|
||||||
@@ -1139,7 +1195,7 @@ public class InstalledAppDetails extends Fragment
|
|||||||
} catch (NameNotFoundException e) {
|
} catch (NameNotFoundException e) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uninstallPkg(packageName);
|
uninstallPkg(packageName, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(v == mActivitiesButton) {
|
} else if(v == mActivitiesButton) {
|
||||||
@@ -1160,7 +1216,7 @@ public class InstalledAppDetails extends Fragment
|
|||||||
Intent intent = new Intent(Intent.ACTION_DEFAULT);
|
Intent intent = new Intent(Intent.ACTION_DEFAULT);
|
||||||
intent.setClassName(mAppEntry.info.packageName,
|
intent.setClassName(mAppEntry.info.packageName,
|
||||||
mAppEntry.info.manageSpaceActivityName);
|
mAppEntry.info.manageSpaceActivityName);
|
||||||
startActivityForResult(intent, -1);
|
startActivityForResult(intent, REQUEST_MANAGE_SPACE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showDialogInner(DLG_CLEAR_DATA, 0);
|
showDialogInner(DLG_CLEAR_DATA, 0);
|
||||||
|
@@ -774,8 +774,12 @@ public class ManageApplications extends Fragment implements
|
|||||||
holder.appIcon.setImageDrawable(entry.icon);
|
holder.appIcon.setImageDrawable(entry.icon);
|
||||||
}
|
}
|
||||||
holder.updateSizeText(mTab.mInvalidSizeStr, mWhichSize);
|
holder.updateSizeText(mTab.mInvalidSizeStr, mWhichSize);
|
||||||
if (InstalledAppDetails.SUPPORT_DISABLE_APPS) {
|
if ((entry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
|
||||||
holder.disabled.setVisibility(entry.info.enabled ? View.GONE : View.VISIBLE);
|
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 {
|
} else {
|
||||||
holder.disabled.setVisibility(View.GONE);
|
holder.disabled.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
@@ -997,7 +1001,6 @@ public class ManageApplications extends Fragment implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
Log.i(TAG, "onCreateOptionsMenu in " + this + ": " + menu);
|
|
||||||
mOptionsMenu = menu;
|
mOptionsMenu = menu;
|
||||||
// note: icons removed for now because the cause the new action
|
// note: icons removed for now because the cause the new action
|
||||||
// bar UI to be very confusing.
|
// bar UI to be very confusing.
|
||||||
|
Reference in New Issue
Block a user