Home | History | Annotate | Download | only in packageinstaller
      1 /*
      2 **
      3 ** Copyright 2007, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 package com.android.packageinstaller;
     18 
     19 import android.app.Activity;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.pm.ApplicationInfo;
     23 import android.content.pm.IPackageDeleteObserver;
     24 import android.content.pm.IPackageDeleteObserver2;
     25 import android.content.pm.IPackageManager;
     26 import android.content.pm.PackageInstaller;
     27 import android.content.pm.PackageManager;
     28 import android.content.pm.UserInfo;
     29 import android.os.Bundle;
     30 import android.os.Handler;
     31 import android.os.IBinder;
     32 import android.os.Message;
     33 import android.os.RemoteException;
     34 import android.os.ServiceManager;
     35 import android.os.UserHandle;
     36 import android.os.UserManager;
     37 import android.util.Log;
     38 import android.view.KeyEvent;
     39 import android.view.View;
     40 import android.view.View.OnClickListener;
     41 import android.widget.Button;
     42 import android.widget.ProgressBar;
     43 import android.widget.TextView;
     44 import android.widget.Toast;
     45 
     46 import java.util.List;
     47 
     48 /**
     49  * This activity corresponds to a download progress screen that is displayed
     50  * when an application is uninstalled. The result of the application uninstall
     51  * is indicated in the result code that gets set to 0 or 1. The application gets launched
     52  * by an intent with the intent's class name explicitly set to UninstallAppProgress and expects
     53  * the application object of the application to uninstall.
     54  */
     55 public class UninstallAppProgress extends Activity implements OnClickListener {
     56     private final String TAG="UninstallAppProgress";
     57     private boolean localLOGV = false;
     58 
     59     private ApplicationInfo mAppInfo;
     60     private boolean mAllUsers;
     61     private UserHandle mUser;
     62     private IBinder mCallback;
     63 
     64     private TextView mStatusTextView;
     65     private Button mOkButton;
     66     private Button mDeviceManagerButton;
     67     private ProgressBar mProgressBar;
     68     private View mOkPanel;
     69     private volatile int mResultCode = -1;
     70 
     71     private static final int UNINSTALL_COMPLETE = 1;
     72 
     73     private Handler mHandler = new Handler() {
     74         public void handleMessage(Message msg) {
     75             switch (msg.what) {
     76                 case UNINSTALL_COMPLETE:
     77                     mResultCode = msg.arg1;
     78                     final String packageName = (String) msg.obj;
     79 
     80                     if (mCallback != null) {
     81                         final IPackageDeleteObserver2 observer = IPackageDeleteObserver2.Stub
     82                                 .asInterface(mCallback);
     83                         try {
     84                             observer.onPackageDeleted(mAppInfo.packageName, mResultCode,
     85                                     packageName);
     86                         } catch (RemoteException ignored) {
     87                         }
     88                         finish();
     89                         return;
     90                     }
     91 
     92                     if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
     93                         Intent result = new Intent();
     94                         result.putExtra(Intent.EXTRA_INSTALL_RESULT, mResultCode);
     95                         setResult(mResultCode == PackageManager.DELETE_SUCCEEDED
     96                                 ? Activity.RESULT_OK : Activity.RESULT_FIRST_USER,
     97                                         result);
     98                         finish();
     99                         return;
    100                     }
    101 
    102                     // Update the status text
    103                     final String statusText;
    104                     switch (msg.arg1) {
    105                         case PackageManager.DELETE_SUCCEEDED:
    106                             statusText = getString(R.string.uninstall_done);
    107                             // Show a Toast and finish the activity
    108                             Context ctx = getBaseContext();
    109                             Toast.makeText(ctx, statusText, Toast.LENGTH_LONG).show();
    110                             setResultAndFinish(mResultCode);
    111                             return;
    112                         case PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER:
    113                             Log.d(TAG, "Uninstall failed because " + packageName
    114                                     + " is a device admin");
    115                             mDeviceManagerButton.setVisibility(View.VISIBLE);
    116                             statusText = getString(R.string.uninstall_failed_device_policy_manager);
    117                             break;
    118                         case PackageManager.DELETE_FAILED_OWNER_BLOCKED:
    119                             UserManager userManager =
    120                                     (UserManager) getSystemService(Context.USER_SERVICE);
    121                             IPackageManager packageManager = IPackageManager.Stub.asInterface(
    122                                     ServiceManager.getService("package"));
    123                             List<UserInfo> users = userManager.getUsers();
    124                             int blockingUserId = UserHandle.USER_NULL;
    125                             for (int i = 0; i < users.size(); ++i) {
    126                                 final UserInfo user = users.get(i);
    127                                 try {
    128                                     if (packageManager.getBlockUninstallForUser(packageName,
    129                                             user.id)) {
    130                                         blockingUserId = user.id;
    131                                         break;
    132                                     }
    133                                 } catch (RemoteException e) {
    134                                     // Shouldn't happen.
    135                                     Log.e(TAG, "Failed to talk to package manager", e);
    136                                 }
    137                             }
    138                             mDeviceManagerButton.setVisibility(View.VISIBLE);
    139                             if (blockingUserId == UserHandle.USER_OWNER) {
    140                                 statusText = getString(R.string.uninstall_blocked_device_owner);
    141                             } else if (blockingUserId == UserHandle.USER_NULL) {
    142                                 Log.d(TAG, "Uninstall failed for " + packageName + " with code "
    143                                         + msg.arg1 + " no blocking user");
    144                                 statusText = getString(R.string.uninstall_failed);
    145                             } else {
    146                                 String userName = userManager.getUserInfo(blockingUserId).name;
    147                                 statusText = String.format(
    148                                         getString(R.string.uninstall_blocked_profile_owner),
    149                                         userName);
    150                             }
    151                             break;
    152                         default:
    153                             Log.d(TAG, "Uninstall failed for " + packageName + " with code "
    154                                     + msg.arg1);
    155                             statusText = getString(R.string.uninstall_failed);
    156                             break;
    157                     }
    158                     mStatusTextView.setText(statusText);
    159 
    160                     // Hide the progress bar; Show the ok button
    161                     mProgressBar.setVisibility(View.INVISIBLE);
    162                     mOkPanel.setVisibility(View.VISIBLE);
    163                     break;
    164                 default:
    165                     break;
    166             }
    167         }
    168     };
    169 
    170     @Override
    171     public void onCreate(Bundle icicle) {
    172         super.onCreate(icicle);
    173         Intent intent = getIntent();
    174         mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
    175         mAllUsers = intent.getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, false);
    176         if (mAllUsers && UserHandle.myUserId() != UserHandle.USER_OWNER) {
    177             throw new SecurityException("Only owner user can request uninstall for all users");
    178         }
    179         mUser = intent.getParcelableExtra(Intent.EXTRA_USER);
    180         if (mUser == null) {
    181             mUser = android.os.Process.myUserHandle();
    182         } else {
    183             UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
    184             List<UserHandle> profiles = userManager.getUserProfiles();
    185             if (!profiles.contains(mUser)) {
    186                 throw new SecurityException("User " + android.os.Process.myUserHandle() + " can't "
    187                         + "request uninstall for user " + mUser);
    188             }
    189         }
    190         mCallback = intent.getIBinderExtra(PackageInstaller.EXTRA_CALLBACK);
    191         initView();
    192     }
    193 
    194     class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
    195         public void packageDeleted(String packageName, int returnCode) {
    196             Message msg = mHandler.obtainMessage(UNINSTALL_COMPLETE);
    197             msg.arg1 = returnCode;
    198             msg.obj = packageName;
    199             mHandler.sendMessage(msg);
    200         }
    201     }
    202 
    203     void setResultAndFinish(int retCode) {
    204         setResult(retCode);
    205         finish();
    206     }
    207 
    208     public void initView() {
    209         boolean isUpdate = ((mAppInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
    210         setTitle(isUpdate ? R.string.uninstall_update_title : R.string.uninstall_application_title);
    211 
    212         setContentView(R.layout.uninstall_progress);
    213         // Initialize views
    214         View snippetView = findViewById(R.id.app_snippet);
    215         PackageUtil.initSnippetForInstalledApp(this, mAppInfo, snippetView);
    216         mStatusTextView = (TextView) findViewById(R.id.center_text);
    217         mStatusTextView.setText(R.string.uninstalling);
    218         mDeviceManagerButton = (Button) findViewById(R.id.device_manager_button);
    219         mDeviceManagerButton.setVisibility(View.GONE);
    220         mDeviceManagerButton.setOnClickListener(new OnClickListener() {
    221             @Override
    222             public void onClick(View v) {
    223                 Intent intent = new Intent();
    224                 intent.setClassName("com.android.settings",
    225                         "com.android.settings.Settings$DeviceAdminSettingsActivity");
    226                 intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_NEW_TASK);
    227                 startActivity(intent);
    228                 finish();
    229             }
    230         });
    231         mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
    232         mProgressBar.setIndeterminate(true);
    233         // Hide button till progress is being displayed
    234         mOkPanel = (View) findViewById(R.id.ok_panel);
    235         mOkButton = (Button) findViewById(R.id.ok_button);
    236         mOkButton.setOnClickListener(this);
    237         mOkPanel.setVisibility(View.INVISIBLE);
    238         IPackageManager packageManager =
    239                 IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
    240         PackageDeleteObserver observer = new PackageDeleteObserver();
    241         try {
    242             packageManager.deletePackageAsUser(mAppInfo.packageName, observer,
    243                     mUser.getIdentifier(),
    244                     mAllUsers ? PackageManager.DELETE_ALL_USERS : 0);
    245         } catch (RemoteException e) {
    246             // Shouldn't happen.
    247             Log.e(TAG, "Failed to talk to package manager", e);
    248         }
    249     }
    250 
    251     public void onClick(View v) {
    252         if(v == mOkButton) {
    253             Log.i(TAG, "Finished uninstalling pkg: " + mAppInfo.packageName);
    254             setResultAndFinish(mResultCode);
    255         }
    256     }
    257 
    258     @Override
    259     public boolean dispatchKeyEvent(KeyEvent ev) {
    260         if (ev.getKeyCode() == KeyEvent.KEYCODE_BACK) {
    261             if (mResultCode == -1) {
    262                 // Ignore back key when installation is in progress
    263                 return true;
    264             } else {
    265                 // If installation is done, just set the result code
    266                 setResult(mResultCode);
    267             }
    268         }
    269         return super.dispatchKeyEvent(ev);
    270     }
    271 }
    272