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