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.DialogInterface; 23 import android.content.DialogInterface.OnCancelListener; 24 import android.content.Intent; 25 import android.content.pm.ApplicationInfo; 26 import android.content.pm.IPackageInstallObserver; 27 import android.content.pm.ManifestDigest; 28 import android.content.pm.PackageInfo; 29 import android.content.pm.PackageManager; 30 import android.content.pm.PackageManager.NameNotFoundException; 31 import android.content.pm.ResolveInfo; 32 import android.content.pm.VerificationParams; 33 import android.graphics.drawable.LevelListDrawable; 34 import android.net.Uri; 35 import android.os.Bundle; 36 import android.os.Handler; 37 import android.os.Message; 38 import android.util.Log; 39 import android.view.View; 40 import android.widget.Button; 41 import android.widget.ProgressBar; 42 import android.widget.TextView; 43 44 import java.io.File; 45 import java.util.List; 46 47 /** 48 * This activity corresponds to a download progress screen that is displayed 49 * when the user tries 50 * to install an application bundled as an apk file. The result of the application install 51 * is indicated in the result code that gets set to the corresponding installation status 52 * codes defined in PackageManager. If the package being installed already exists, 53 * the existing package is replaced with the new one. 54 */ 55 public class InstallAppProgress extends Activity implements View.OnClickListener, OnCancelListener { 56 private final String TAG="InstallAppProgress"; 57 private boolean localLOGV = false; 58 static final String EXTRA_MANIFEST_DIGEST = 59 "com.android.packageinstaller.extras.manifest_digest"; 60 private ApplicationInfo mAppInfo; 61 private Uri mPackageURI; 62 private ProgressBar mProgressBar; 63 private View mOkPanel; 64 private TextView mStatusTextView; 65 private TextView mExplanationTextView; 66 private Button mDoneButton; 67 private Button mLaunchButton; 68 private final int INSTALL_COMPLETE = 1; 69 private Intent mLaunchIntent; 70 private static final int DLG_OUT_OF_SPACE = 1; 71 private CharSequence mLabel; 72 73 private Handler mHandler = new Handler() { 74 public void handleMessage(Message msg) { 75 switch (msg.what) { 76 case INSTALL_COMPLETE: 77 if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) { 78 Intent result = new Intent(); 79 result.putExtra(Intent.EXTRA_INSTALL_RESULT, msg.arg1); 80 setResult(msg.arg1 == PackageManager.INSTALL_SUCCEEDED 81 ? Activity.RESULT_OK : Activity.RESULT_FIRST_USER, 82 result); 83 finish(); 84 return; 85 } 86 // Update the status text 87 mProgressBar.setVisibility(View.INVISIBLE); 88 // Show the ok button 89 int centerTextLabel; 90 int centerExplanationLabel = -1; 91 LevelListDrawable centerTextDrawable = (LevelListDrawable) getResources() 92 .getDrawable(R.drawable.ic_result_status); 93 if (msg.arg1 == PackageManager.INSTALL_SUCCEEDED) { 94 mLaunchButton.setVisibility(View.VISIBLE); 95 centerTextDrawable.setLevel(0); 96 centerTextLabel = R.string.install_done; 97 // Enable or disable launch button 98 mLaunchIntent = getPackageManager().getLaunchIntentForPackage( 99 mAppInfo.packageName); 100 boolean enabled = false; 101 if(mLaunchIntent != null) { 102 List<ResolveInfo> list = getPackageManager(). 103 queryIntentActivities(mLaunchIntent, 0); 104 if (list != null && list.size() > 0) { 105 enabled = true; 106 } 107 } 108 if (enabled) { 109 mLaunchButton.setOnClickListener(InstallAppProgress.this); 110 } else { 111 mLaunchButton.setEnabled(false); 112 } 113 } else if (msg.arg1 == PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE){ 114 showDialogInner(DLG_OUT_OF_SPACE); 115 return; 116 } else { 117 // Generic error handling for all other error codes. 118 centerTextDrawable.setLevel(1); 119 centerExplanationLabel = getExplanationFromErrorCode(msg.arg1); 120 centerTextLabel = R.string.install_failed; 121 mLaunchButton.setVisibility(View.INVISIBLE); 122 } 123 if (centerTextDrawable != null) { 124 centerTextDrawable.setBounds(0, 0, 125 centerTextDrawable.getIntrinsicWidth(), 126 centerTextDrawable.getIntrinsicHeight()); 127 mStatusTextView.setCompoundDrawables(centerTextDrawable, null, null, null); 128 } 129 mStatusTextView.setText(centerTextLabel); 130 if (centerExplanationLabel != -1) { 131 mExplanationTextView.setText(centerExplanationLabel); 132 mExplanationTextView.setVisibility(View.VISIBLE); 133 } else { 134 mExplanationTextView.setVisibility(View.GONE); 135 } 136 mDoneButton.setOnClickListener(InstallAppProgress.this); 137 mOkPanel.setVisibility(View.VISIBLE); 138 break; 139 default: 140 break; 141 } 142 } 143 }; 144 145 private int getExplanationFromErrorCode(int errCode) { 146 Log.d(TAG, "Installation error code: " + errCode); 147 switch (errCode) { 148 case PackageManager.INSTALL_FAILED_INVALID_APK: 149 return R.string.install_failed_invalid_apk; 150 case PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: 151 return R.string.install_failed_inconsistent_certificates; 152 case PackageManager.INSTALL_FAILED_OLDER_SDK: 153 return R.string.install_failed_older_sdk; 154 case PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: 155 return R.string.install_failed_cpu_abi_incompatible; 156 default: 157 return -1; 158 } 159 } 160 161 @Override 162 public void onCreate(Bundle icicle) { 163 super.onCreate(icicle); 164 Intent intent = getIntent(); 165 mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); 166 mPackageURI = intent.getData(); 167 168 final String scheme = mPackageURI.getScheme(); 169 if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) { 170 throw new IllegalArgumentException("unexpected scheme " + scheme); 171 } 172 173 initView(); 174 } 175 176 @Override 177 public Dialog onCreateDialog(int id, Bundle bundle) { 178 switch (id) { 179 case DLG_OUT_OF_SPACE: 180 String dlgText = getString(R.string.out_of_space_dlg_text, mLabel); 181 return new AlertDialog.Builder(this) 182 .setTitle(R.string.out_of_space_dlg_title) 183 .setMessage(dlgText) 184 .setPositiveButton(R.string.manage_applications, new DialogInterface.OnClickListener() { 185 public void onClick(DialogInterface dialog, int which) { 186 //launch manage applications 187 Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE"); 188 startActivity(intent); 189 finish(); 190 } 191 }) 192 .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { 193 public void onClick(DialogInterface dialog, int which) { 194 Log.i(TAG, "Canceling installation"); 195 finish(); 196 } 197 }) 198 .setOnCancelListener(this) 199 .create(); 200 } 201 return null; 202 } 203 204 private void showDialogInner(int id) { 205 removeDialog(id); 206 showDialog(id); 207 } 208 209 class PackageInstallObserver extends IPackageInstallObserver.Stub { 210 public void packageInstalled(String packageName, int returnCode) { 211 Message msg = mHandler.obtainMessage(INSTALL_COMPLETE); 212 msg.arg1 = returnCode; 213 mHandler.sendMessage(msg); 214 } 215 } 216 217 public void initView() { 218 setContentView(R.layout.op_progress); 219 int installFlags = 0; 220 PackageManager pm = getPackageManager(); 221 try { 222 PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName, 223 PackageManager.GET_UNINSTALLED_PACKAGES); 224 if(pi != null) { 225 installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; 226 } 227 } catch (NameNotFoundException e) { 228 } 229 if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) { 230 Log.w(TAG, "Replacing package:" + mAppInfo.packageName); 231 } 232 233 final PackageUtil.AppSnippet as; 234 if ("package".equals(mPackageURI.getScheme())) { 235 as = new PackageUtil.AppSnippet(pm.getApplicationLabel(mAppInfo), 236 pm.getApplicationIcon(mAppInfo)); 237 } else { 238 final File sourceFile = new File(mPackageURI.getPath()); 239 as = PackageUtil.getAppSnippet(this, mAppInfo, sourceFile); 240 } 241 mLabel = as.label; 242 PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet); 243 mStatusTextView = (TextView)findViewById(R.id.center_text); 244 mStatusTextView.setText(R.string.installing); 245 mExplanationTextView = (TextView) findViewById(R.id.center_explanation); 246 mProgressBar = (ProgressBar) findViewById(R.id.progress_bar); 247 mProgressBar.setIndeterminate(true); 248 // Hide button till progress is being displayed 249 mOkPanel = (View)findViewById(R.id.buttons_panel); 250 mDoneButton = (Button)findViewById(R.id.done_button); 251 mLaunchButton = (Button)findViewById(R.id.launch_button); 252 mOkPanel.setVisibility(View.INVISIBLE); 253 254 String installerPackageName = getIntent().getStringExtra( 255 Intent.EXTRA_INSTALLER_PACKAGE_NAME); 256 Uri originatingURI = getIntent().getParcelableExtra(Intent.EXTRA_ORIGINATING_URI); 257 Uri referrer = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER); 258 int originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID, 259 VerificationParams.NO_UID); 260 ManifestDigest manifestDigest = getIntent().getParcelableExtra(EXTRA_MANIFEST_DIGEST); 261 VerificationParams verificationParams = new VerificationParams(null, originatingURI, 262 referrer, originatingUid, manifestDigest); 263 PackageInstallObserver observer = new PackageInstallObserver(); 264 265 if ("package".equals(mPackageURI.getScheme())) { 266 try { 267 pm.installExistingPackage(mAppInfo.packageName); 268 observer.packageInstalled(mAppInfo.packageName, 269 PackageManager.INSTALL_SUCCEEDED); 270 } catch (PackageManager.NameNotFoundException e) { 271 observer.packageInstalled(mAppInfo.packageName, 272 PackageManager.INSTALL_FAILED_INVALID_APK); 273 } 274 } else { 275 pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags, 276 installerPackageName, verificationParams, null); 277 } 278 } 279 280 @Override 281 protected void onDestroy() { 282 super.onDestroy(); 283 } 284 285 public void onClick(View v) { 286 if(v == mDoneButton) { 287 if (mAppInfo.packageName != null) { 288 Log.i(TAG, "Finished installing "+mAppInfo.packageName); 289 } 290 finish(); 291 } else if(v == mLaunchButton) { 292 startActivity(mLaunchIntent); 293 finish(); 294 } 295 } 296 297 public void onCancel(DialogInterface dialog) { 298 finish(); 299 } 300 } 301