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.app.AlertDialog; 21 import android.app.Dialog; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.DialogInterface; 25 import android.content.Intent; 26 import android.content.pm.ActivityInfo; 27 import android.content.pm.ApplicationInfo; 28 import android.content.pm.PackageManager; 29 import android.content.pm.PackageManager.NameNotFoundException; 30 import android.content.pm.ResolveInfo; 31 import android.graphics.drawable.Drawable; 32 import android.net.Uri; 33 import android.os.Bundle; 34 import android.os.UserManager; 35 import android.util.Log; 36 import android.view.LayoutInflater; 37 import android.view.View; 38 import android.view.View.OnClickListener; 39 import android.view.ViewGroup; 40 import android.view.Window; 41 import android.widget.Button; 42 import android.widget.TextView; 43 44 import java.util.List; 45 46 /* 47 * This activity presents UI to uninstall an application. Usually launched with intent 48 * Intent.ACTION_UNINSTALL_PKG_COMMAND and attribute 49 * com.android.packageinstaller.PackageName set to the application package name 50 */ 51 public class UninstallerActivity extends Activity implements OnClickListener, 52 DialogInterface.OnCancelListener { 53 private static final String TAG = "UninstallerActivity"; 54 private boolean localLOGV = false; 55 PackageManager mPm; 56 private ApplicationInfo mAppInfo; 57 private boolean mAllUsers; 58 private Button mOk; 59 private Button mCancel; 60 61 // Dialog identifiers used in showDialog 62 private static final int DLG_BASE = 0; 63 private static final int DLG_APP_NOT_FOUND = DLG_BASE + 1; 64 private static final int DLG_UNINSTALL_FAILED = DLG_BASE + 2; 65 66 @Override onCreateDialog(int id)67 public Dialog onCreateDialog(int id) { 68 switch (id) { 69 case DLG_APP_NOT_FOUND : 70 return new AlertDialog.Builder(this) 71 .setTitle(R.string.app_not_found_dlg_title) 72 .setIcon(com.android.internal.R.drawable.ic_dialog_alert) 73 .setMessage(R.string.app_not_found_dlg_text) 74 .setNeutralButton(getString(R.string.dlg_ok), 75 new DialogInterface.OnClickListener() { 76 public void onClick(DialogInterface dialog, int which) { 77 setResult(Activity.RESULT_FIRST_USER); 78 finish(); 79 }}) 80 .create(); 81 case DLG_UNINSTALL_FAILED : 82 // Guaranteed not to be null. will default to package name if not set by app 83 CharSequence appTitle = mPm.getApplicationLabel(mAppInfo); 84 String dlgText = getString(R.string.uninstall_failed_msg, 85 appTitle.toString()); 86 // Display uninstall failed dialog 87 return new AlertDialog.Builder(this) 88 .setTitle(R.string.uninstall_failed) 89 .setIcon(com.android.internal.R.drawable.ic_dialog_alert) 90 .setMessage(dlgText) 91 .setNeutralButton(getString(R.string.dlg_ok), 92 new DialogInterface.OnClickListener() { 93 public void onClick(DialogInterface dialog, int which) { 94 setResult(Activity.RESULT_FIRST_USER); 95 finish(); 96 }}) 97 .create(); 98 } 99 return null; 100 } 101 102 private void startUninstallProgress() { 103 Intent newIntent = new Intent(Intent.ACTION_VIEW); 104 newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, 105 mAppInfo); 106 newIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, mAllUsers); 107 if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) { 108 newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true); 109 newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); 110 } 111 newIntent.setClass(this, UninstallAppProgress.class); 112 startActivity(newIntent); 113 finish(); 114 } 115 116 @Override 117 public void onCreate(Bundle icicle) { 118 super.onCreate(icicle); 119 // Get intent information. 120 // We expect an intent with URI of the form package://<packageName>#<className> 121 // className is optional; if specified, it is the activity the user chose to uninstall 122 final Intent intent = getIntent(); 123 Uri packageURI = intent.getData(); 124 String packageName = packageURI.getEncodedSchemeSpecificPart(); 125 if(packageName == null) { 126 Log.e(TAG, "Invalid package name:" + packageName); 127 showDialog(DLG_APP_NOT_FOUND); 128 return; 129 } 130 131 mPm = getPackageManager(); 132 boolean errFlag = false; 133 try { 134 mAppInfo = mPm.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES); 135 } catch (NameNotFoundException e) { 136 errFlag = true; 137 } 138 139 mAllUsers = intent.getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, false); 140 141 // The class name may have been specified (e.g. when deleting an app from all apps) 142 String className = packageURI.getFragment(); 143 ActivityInfo activityInfo = null; 144 if (className != null) { 145 try { 146 activityInfo = mPm.getActivityInfo(new ComponentName(packageName, className), 0); 147 } catch (NameNotFoundException e) { 148 errFlag = true; 149 } 150 } 151 152 if(mAppInfo == null || errFlag) { 153 Log.e(TAG, "Invalid packageName or componentName in " + packageURI.toString()); 154 showDialog(DLG_APP_NOT_FOUND); 155 } else { 156 boolean isUpdate = ((mAppInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0); 157 158 setContentView(R.layout.uninstall_confirm); 159 160 TextView confirm = (TextView) findViewById(R.id.uninstall_confirm); 161 if (isUpdate) { 162 setTitle(R.string.uninstall_update_title); 163 confirm.setText(R.string.uninstall_update_text); 164 } else { 165 setTitle(R.string.uninstall_application_title); 166 if (mAllUsers && ((UserManager)getSystemService( 167 Context.USER_SERVICE)).getUsers().size() >= 2) { 168 confirm.setText(R.string.uninstall_application_text_all_users); 169 } else { 170 confirm.setText(R.string.uninstall_application_text); 171 } 172 } 173 174 // If an activity was specified (e.g. when dragging from All Apps to trash can), 175 // give a bit more info if the activity label isn't the same as the package label. 176 if (activityInfo != null) { 177 CharSequence activityLabel = activityInfo.loadLabel(mPm); 178 if (!activityLabel.equals(mAppInfo.loadLabel(mPm))) { 179 TextView activityText = (TextView) findViewById(R.id.activity_text); 180 CharSequence text = getString(R.string.uninstall_activity_text, activityLabel); 181 activityText.setText(text); 182 activityText.setVisibility(View.VISIBLE); 183 } 184 } 185 186 View snippetView = findViewById(R.id.uninstall_activity_snippet); 187 PackageUtil.initSnippetForInstalledApp(this, mAppInfo, snippetView); 188 189 //initialize ui elements 190 mOk = (Button)findViewById(R.id.ok_button); 191 mCancel = (Button)findViewById(R.id.cancel_button); 192 mOk.setOnClickListener(this); 193 mCancel.setOnClickListener(this); 194 } 195 } 196 197 public void onClick(View v) { 198 if(v == mOk) { 199 //initiate next screen 200 startUninstallProgress(); 201 } else if(v == mCancel) { 202 finish(); 203 } 204 } 205 206 public void onCancel(DialogInterface dialog) { 207 finish(); 208 } 209 } 210