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
onCreate(Bundle icicle)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 {
packageDeleted(String packageName, int returnCode)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 
setResultAndFinish(int retCode)203     void setResultAndFinish(int retCode) {
204         setResult(retCode);
205         finish();
206     }
207 
initView()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 
onClick(View v)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
dispatchKeyEvent(KeyEvent ev)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