diff options
Diffstat (limited to 'src')
3 files changed, 124 insertions, 22 deletions
diff --git a/src/com/android/packageinstaller/PackageUtil.java b/src/com/android/packageinstaller/PackageUtil.java index 63121e4a..bb445824 100644 --- a/src/com/android/packageinstaller/PackageUtil.java +++ b/src/com/android/packageinstaller/PackageUtil.java @@ -18,6 +18,7 @@ package com.android.packageinstaller; import android.app.Activity; +import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -30,6 +31,8 @@ import android.util.DisplayMetrics; import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import android.os.UserHandle; +import android.os.UserManager; import java.io.File; import java.util.List; @@ -91,11 +94,33 @@ public class PackageUtil { */ public static View initSnippetForInstalledApp(Activity pContext, ApplicationInfo appInfo, View snippetView) { + return initSnippetForInstalledApp(pContext, appInfo, snippetView, null); + } + + /** + * Utility method to display a snippet of an installed application. + * The content view should have been set on context before invoking this method. + * appSnippet view should include R.id.app_icon and R.id.app_name + * defined on it. + * + * @param pContext context of package that can load the resources + * @param componentInfo ComponentInfo object whose resources are to be loaded + * @param snippetView the snippet view + * @param UserHandle user that the app si installed for. + */ + public static View initSnippetForInstalledApp(Activity pContext, + ApplicationInfo appInfo, View snippetView, UserHandle user) { final PackageManager pm = pContext.getPackageManager(); + Drawable icon = appInfo.loadIcon(pm); + if (user != null) { + final UserManager userManager = (UserManager) pContext.getSystemService( + Context.USER_SERVICE); + icon = userManager.getBadgedDrawableForUser(icon, user); + } return initSnippet( snippetView, appInfo.loadLabel(pm), - appInfo.loadIcon(pm)); + icon); } /** diff --git a/src/com/android/packageinstaller/UninstallAppProgress.java b/src/com/android/packageinstaller/UninstallAppProgress.java index 7aa0a2e0..397236a6 100755 --- a/src/com/android/packageinstaller/UninstallAppProgress.java +++ b/src/com/android/packageinstaller/UninstallAppProgress.java @@ -21,10 +21,16 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageDeleteObserver; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.UserHandle; +import android.os.UserManager; import android.util.Log; import android.view.KeyEvent; import android.view.View; @@ -34,6 +40,8 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; +import java.util.List; + /** * This activity corresponds to a download progress screen that is displayed * when an application is uninstalled. The result of the application uninstall @@ -46,6 +54,7 @@ public class UninstallAppProgress extends Activity implements OnClickListener { private boolean localLOGV = false; private ApplicationInfo mAppInfo; private boolean mAllUsers; + private UserHandle mUser; private TextView mStatusTextView; private Button mOkButton; private Button mDeviceManagerButton; @@ -73,10 +82,10 @@ public class UninstallAppProgress extends Activity implements OnClickListener { final String packageName = (String) msg.obj; // Update the status text - final int statusText; + final String statusText; switch (msg.arg1) { case PackageManager.DELETE_SUCCEEDED: - statusText = R.string.uninstall_done; + statusText = getString(R.string.uninstall_done); // Show a Toast and finish the activity Context ctx = getBaseContext(); Toast.makeText(ctx, statusText, Toast.LENGTH_LONG).show(); @@ -86,12 +95,46 @@ public class UninstallAppProgress extends Activity implements OnClickListener { Log.d(TAG, "Uninstall failed because " + packageName + " is a device admin"); mDeviceManagerButton.setVisibility(View.VISIBLE); - statusText = R.string.uninstall_failed_device_policy_manager; + statusText = getString(R.string.uninstall_failed_device_policy_manager); + break; + case PackageManager.DELETE_FAILED_OWNER_BLOCKED: + UserManager userManager = + (UserManager) getSystemService(Context.USER_SERVICE); + IPackageManager packageManager = IPackageManager.Stub.asInterface( + ServiceManager.getService("package")); + List<UserInfo> users = userManager.getUsers(); + int blockingUserId = UserHandle.USER_NULL; + for (int i = 0; i < users.size(); ++i) { + final UserInfo user = users.get(i); + try { + if (packageManager.getBlockUninstallForUser(packageName, + user.id)) { + blockingUserId = user.id; + break; + } + } catch (RemoteException e) { + // Shouldn't happen. + Log.e(TAG, "Failed to talk to package manager", e); + } + } + mDeviceManagerButton.setVisibility(View.VISIBLE); + if (blockingUserId == UserHandle.USER_OWNER) { + statusText = getString(R.string.uninstall_blocked_device_owner); + } else if (blockingUserId == UserHandle.USER_NULL) { + Log.d(TAG, "Uninstall failed for " + packageName + " with code " + + msg.arg1 + " no blocking user"); + statusText = getString(R.string.uninstall_failed); + } else { + String userName = userManager.getUserInfo(blockingUserId).name; + statusText = String.format( + getString(R.string.uninstall_blocked_profile_owner), + userName); + } break; default: Log.d(TAG, "Uninstall failed for " + packageName + " with code " + msg.arg1); - statusText = R.string.uninstall_failed; + statusText = getString(R.string.uninstall_failed); break; } mStatusTextView.setText(statusText); @@ -112,6 +155,20 @@ public class UninstallAppProgress extends Activity implements OnClickListener { Intent intent = getIntent(); mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); mAllUsers = intent.getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, false); + if (mAllUsers && UserHandle.myUserId() != UserHandle.USER_OWNER) { + throw new SecurityException("Only owner user can request uninstall for all users"); + } + mUser = intent.getParcelableExtra(Intent.EXTRA_USER); + if (mUser == null) { + mUser = android.os.Process.myUserHandle(); + } else { + UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); + List<UserHandle> profiles = userManager.getUserProfiles(); + if (!profiles.contains(mUser)) { + throw new SecurityException("User " + android.os.Process.myUserHandle() + " can't " + + "request uninstall for user " + mUser); + } + } initView(); } @@ -159,9 +216,17 @@ public class UninstallAppProgress extends Activity implements OnClickListener { mOkButton = (Button) findViewById(R.id.ok_button); mOkButton.setOnClickListener(this); mOkPanel.setVisibility(View.INVISIBLE); + IPackageManager packageManager = + IPackageManager.Stub.asInterface(ServiceManager.getService("package")); PackageDeleteObserver observer = new PackageDeleteObserver(); - getPackageManager().deletePackage(mAppInfo.packageName, observer, - mAllUsers ? PackageManager.DELETE_ALL_USERS : 0); + try { + packageManager.deletePackageAsUser(mAppInfo.packageName, observer, + mUser.getIdentifier(), + mAllUsers ? PackageManager.DELETE_ALL_USERS : 0); + } catch (RemoteException e) { + // Shouldn't happen. + Log.e(TAG, "Failed to talk to package manager", e); + } } public void onClick(View v) { diff --git a/src/com/android/packageinstaller/UninstallerActivity.java b/src/com/android/packageinstaller/UninstallerActivity.java index 1b9bdce9..b64ce6f4 100755 --- a/src/com/android/packageinstaller/UninstallerActivity.java +++ b/src/com/android/packageinstaller/UninstallerActivity.java @@ -25,24 +25,20 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.ResolveInfo; -import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.UserHandle; import android.os.UserManager; import android.util.Log; -import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.Window; import android.widget.Button; import android.widget.TextView; -import java.util.List; - /* * This activity presents UI to uninstall an application. Usually launched with intent * Intent.ACTION_UNINSTALL_PKG_COMMAND and attribute @@ -53,10 +49,12 @@ public class UninstallerActivity extends Activity implements OnClickListener, private static final String TAG = "UninstallerActivity"; private boolean localLOGV = false; PackageManager mPm; + private IPackageManager mIpm; private ApplicationInfo mAppInfo; private boolean mAllUsers; private Button mOk; private Button mCancel; + private UserHandle mUserHandle; // Dialog identifiers used in showDialog private static final int DLG_BASE = 0; @@ -104,6 +102,7 @@ public class UninstallerActivity extends Activity implements OnClickListener, newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mAppInfo); newIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, mAllUsers); + newIntent.putExtra(Intent.EXTRA_USER, mUserHandle); if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) { newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true); newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); @@ -128,11 +127,19 @@ public class UninstallerActivity extends Activity implements OnClickListener, return; } + mUserHandle = intent.getParcelableExtra(Intent.EXTRA_USER); + if (mUserHandle == null) { + mUserHandle = android.os.Process.myUserHandle(); + } + mPm = getPackageManager(); + mIpm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); + boolean errFlag = false; try { - mAppInfo = mPm.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES); - } catch (NameNotFoundException e) { + mAppInfo = mIpm.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES, + mUserHandle.getIdentifier()); + } catch (RemoteException e) { errFlag = true; } @@ -143,8 +150,9 @@ public class UninstallerActivity extends Activity implements OnClickListener, ActivityInfo activityInfo = null; if (className != null) { try { - activityInfo = mPm.getActivityInfo(new ComponentName(packageName, className), 0); - } catch (NameNotFoundException e) { + activityInfo = mIpm.getActivityInfo(new ComponentName(packageName, className), 0, + mUserHandle.getIdentifier()); + } catch (RemoteException e) { errFlag = true; } } @@ -162,10 +170,14 @@ public class UninstallerActivity extends Activity implements OnClickListener, setTitle(R.string.uninstall_update_title); confirm.setText(R.string.uninstall_update_text); } else { + UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); setTitle(R.string.uninstall_application_title); - if (mAllUsers && ((UserManager)getSystemService( - Context.USER_SERVICE)).getUsers().size() >= 2) { + if (mAllUsers && userManager.getUsers().size() >= 2) { confirm.setText(R.string.uninstall_application_text_all_users); + } else if (!mUserHandle.equals(android.os.Process.myUserHandle())) { + String userName = userManager.getUserInfo(mUserHandle.getIdentifier()).name; + confirm.setText(String.format( + getString(R.string.uninstall_application_text_user), userName)); } else { confirm.setText(R.string.uninstall_application_text); } @@ -184,7 +196,7 @@ public class UninstallerActivity extends Activity implements OnClickListener, } View snippetView = findViewById(R.id.uninstall_activity_snippet); - PackageUtil.initSnippetForInstalledApp(this, mAppInfo, snippetView); + PackageUtil.initSnippetForInstalledApp(this, mAppInfo, snippetView, mUserHandle); //initialize ui elements mOk = (Button)findViewById(R.id.ok_button); |