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