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.ActivityManagerNative; 21 import android.app.AlertDialog; 22 import android.app.Dialog; 23 import android.content.Context; 24 import android.content.DialogInterface; 25 import android.content.DialogInterface.OnCancelListener; 26 import android.content.Intent; 27 import android.content.SharedPreferences; 28 import android.content.pm.ApplicationInfo; 29 import android.content.pm.ManifestDigest; 30 import android.content.pm.PackageInfo; 31 import android.content.pm.PackageManager; 32 import android.content.pm.PackageManager.NameNotFoundException; 33 import android.content.pm.PackageParser; 34 import android.content.pm.PackageUserState; 35 import android.content.pm.ResolveInfo; 36 import android.content.pm.VerificationParams; 37 import android.net.Uri; 38 import android.os.Bundle; 39 import android.os.SystemClock; 40 import android.provider.Settings; 41 import android.support.v4.view.ViewPager; 42 import android.util.Log; 43 import android.view.LayoutInflater; 44 import android.view.View; 45 import android.view.View.OnClickListener; 46 import android.view.ViewGroup; 47 import android.widget.AppSecurityPermissions; 48 import android.widget.Button; 49 import android.widget.TabHost; 50 import android.widget.TextView; 51 52 import java.io.File; 53 import java.util.List; 54 55 /* 56 * This activity is launched when a new application is installed via side loading 57 * The package is first parsed and the user is notified of parse errors via a dialog. 58 * If the package is successfully parsed, the user is notified to turn on the install unknown 59 * applications setting. A memory check is made at this point and the user is notified of out 60 * of memory conditions if any. If the package is already existing on the device, 61 * a confirmation dialog (to replace the existing package) is presented to the user. 62 * Based on the user response the package is then installed by launching InstallAppConfirm 63 * sub activity. All state transitions are handled in this activity 64 */ 65 public class PackageInstallerActivity extends Activity implements OnCancelListener, OnClickListener { 66 private static final String TAG = "PackageInstaller"; 67 private Uri mPackageURI; 68 private Uri mOriginatingURI; 69 private Uri mReferrerURI; 70 private int mOriginatingUid = VerificationParams.NO_UID; 71 private ManifestDigest mPkgDigest; 72 73 private boolean localLOGV = false; 74 PackageManager mPm; 75 PackageInfo mPkgInfo; 76 ApplicationInfo mSourceInfo; 77 78 // ApplicationInfo object primarily used for already existing applications 79 private ApplicationInfo mAppInfo = null; 80 81 private InstallFlowAnalytics mInstallFlowAnalytics; 82 83 // View for install progress 84 View mInstallConfirm; 85 // Buttons to indicate user acceptance 86 private Button mOk; 87 private Button mCancel; 88 CaffeinatedScrollView mScrollView = null; 89 private boolean mOkCanInstall = false; 90 91 static final String PREFS_ALLOWED_SOURCES = "allowed_sources"; 92 93 private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; 94 95 private static final String TAB_ID_ALL = "all"; 96 private static final String TAB_ID_NEW = "new"; 97 98 // Dialog identifiers used in showDialog 99 private static final int DLG_BASE = 0; 100 private static final int DLG_UNKNOWN_APPS = DLG_BASE + 1; 101 private static final int DLG_PACKAGE_ERROR = DLG_BASE + 2; 102 private static final int DLG_OUT_OF_SPACE = DLG_BASE + 3; 103 private static final int DLG_INSTALL_ERROR = DLG_BASE + 4; 104 private static final int DLG_ALLOW_SOURCE = DLG_BASE + 5; 105 106 private void startInstallConfirm() { 107 TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost); 108 tabHost.setup(); 109 ViewPager viewPager = (ViewPager)findViewById(R.id.pager); 110 TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager); 111 adapter.setOnTabChangedListener(new TabHost.OnTabChangeListener() { 112 @Override 113 public void onTabChanged(String tabId) { 114 if (TAB_ID_ALL.equals(tabId)) { 115 mInstallFlowAnalytics.setAllPermissionsDisplayed(true); 116 } else if (TAB_ID_NEW.equals(tabId)) { 117 mInstallFlowAnalytics.setNewPermissionsDisplayed(true); 118 } 119 } 120 }); 121 122 boolean permVisible = false; 123 mScrollView = null; 124 mOkCanInstall = false; 125 int msg = 0; 126 if (mPkgInfo != null) { 127 AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo); 128 final int NP = perms.getPermissionCount(AppSecurityPermissions.WHICH_PERSONAL); 129 final int ND = perms.getPermissionCount(AppSecurityPermissions.WHICH_DEVICE); 130 if (mAppInfo != null) { 131 msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 132 ? R.string.install_confirm_question_update_system 133 : R.string.install_confirm_question_update; 134 mScrollView = new CaffeinatedScrollView(this); 135 mScrollView.setFillViewport(true); 136 boolean newPermissionsFound = 137 (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0); 138 mInstallFlowAnalytics.setNewPermissionsFound(newPermissionsFound); 139 if (newPermissionsFound) { 140 permVisible = true; 141 mScrollView.addView(perms.getPermissionsView( 142 AppSecurityPermissions.WHICH_NEW)); 143 } else { 144 LayoutInflater inflater = (LayoutInflater)getSystemService( 145 Context.LAYOUT_INFLATER_SERVICE); 146 TextView label = (TextView)inflater.inflate(R.layout.label, null); 147 label.setText(R.string.no_new_perms); 148 mScrollView.addView(label); 149 } 150 adapter.addTab(tabHost.newTabSpec(TAB_ID_NEW).setIndicator( 151 getText(R.string.newPerms)), mScrollView); 152 } else { 153 findViewById(R.id.tabscontainer).setVisibility(View.GONE); 154 findViewById(R.id.divider).setVisibility(View.VISIBLE); 155 } 156 if (NP > 0 || ND > 0) { 157 permVisible = true; 158 LayoutInflater inflater = (LayoutInflater)getSystemService( 159 Context.LAYOUT_INFLATER_SERVICE); 160 View root = inflater.inflate(R.layout.permissions_list, null); 161 if (mScrollView == null) { 162 mScrollView = (CaffeinatedScrollView)root.findViewById(R.id.scrollview); 163 } 164 if (NP > 0) { 165 ((ViewGroup)root.findViewById(R.id.privacylist)).addView( 166 perms.getPermissionsView(AppSecurityPermissions.WHICH_PERSONAL)); 167 } else { 168 root.findViewById(R.id.privacylist).setVisibility(View.GONE); 169 } 170 if (ND > 0) { 171 ((ViewGroup)root.findViewById(R.id.devicelist)).addView( 172 perms.getPermissionsView(AppSecurityPermissions.WHICH_DEVICE)); 173 } else { 174 root.findViewById(R.id.devicelist).setVisibility(View.GONE); 175 } 176 adapter.addTab(tabHost.newTabSpec(TAB_ID_ALL).setIndicator( 177 getText(R.string.allPerms)), root); 178 } 179 } 180 mInstallFlowAnalytics.setPermissionsDisplayed(permVisible); 181 if (!permVisible) { 182 if (mAppInfo != null) { 183 // This is an update to an application, but there are no 184 // permissions at all. 185 msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 186 ? R.string.install_confirm_question_update_system_no_perms 187 : R.string.install_confirm_question_update_no_perms; 188 } else { 189 // This is a new application with no permissions. 190 msg = R.string.install_confirm_question_no_perms; 191 } 192 tabHost.setVisibility(View.GONE); 193 mInstallFlowAnalytics.setAllPermissionsDisplayed(false); 194 mInstallFlowAnalytics.setNewPermissionsDisplayed(false); 195 findViewById(R.id.filler).setVisibility(View.VISIBLE); 196 findViewById(R.id.divider).setVisibility(View.GONE); 197 mScrollView = null; 198 } 199 if (msg != 0) { 200 ((TextView)findViewById(R.id.install_confirm_question)).setText(msg); 201 } 202 mInstallConfirm.setVisibility(View.VISIBLE); 203 mOk = (Button)findViewById(R.id.ok_button); 204 mCancel = (Button)findViewById(R.id.cancel_button); 205 mOk.setOnClickListener(this); 206 mCancel.setOnClickListener(this); 207 if (mScrollView == null) { 208 // There is nothing to scroll view, so the ok button is immediately 209 // set to install. 210 mOk.setText(R.string.install); 211 mOkCanInstall = true; 212 } else { 213 mScrollView.setFullScrollAction(new Runnable() { 214 @Override 215 public void run() { 216 mOk.setText(R.string.install); 217 mOkCanInstall = true; 218 } 219 }); 220 } 221 } 222 223 private void showDialogInner(int id) { 224 // TODO better fix for this? Remove dialog so that it gets created again 225 removeDialog(id); 226 showDialog(id); 227 } 228 229 @Override 230 public Dialog onCreateDialog(int id, Bundle bundle) { 231 switch (id) { 232 case DLG_UNKNOWN_APPS: 233 return new AlertDialog.Builder(this) 234 .setTitle(R.string.unknown_apps_dlg_title) 235 .setMessage(R.string.unknown_apps_dlg_text) 236 .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { 237 public void onClick(DialogInterface dialog, int which) { 238 Log.i(TAG, "Finishing off activity so that user can navigate to settings manually"); 239 finish(); 240 }}) 241 .setPositiveButton(R.string.settings, new DialogInterface.OnClickListener() { 242 public void onClick(DialogInterface dialog, int which) { 243 Log.i(TAG, "Launching settings"); 244 launchSettingsAppAndFinish(); 245 } 246 }) 247 .setOnCancelListener(this) 248 .create(); 249 case DLG_PACKAGE_ERROR : 250 return new AlertDialog.Builder(this) 251 .setTitle(R.string.Parse_error_dlg_title) 252 .setMessage(R.string.Parse_error_dlg_text) 253 .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { 254 public void onClick(DialogInterface dialog, int which) { 255 finish(); 256 } 257 }) 258 .setOnCancelListener(this) 259 .create(); 260 case DLG_OUT_OF_SPACE: 261 // Guaranteed not to be null. will default to package name if not set by app 262 CharSequence appTitle = mPm.getApplicationLabel(mPkgInfo.applicationInfo); 263 String dlgText = getString(R.string.out_of_space_dlg_text, 264 appTitle.toString()); 265 return new AlertDialog.Builder(this) 266 .setTitle(R.string.out_of_space_dlg_title) 267 .setMessage(dlgText) 268 .setPositiveButton(R.string.manage_applications, new DialogInterface.OnClickListener() { 269 public void onClick(DialogInterface dialog, int which) { 270 //launch manage applications 271 Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE"); 272 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 273 startActivity(intent); 274 finish(); 275 } 276 }) 277 .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { 278 public void onClick(DialogInterface dialog, int which) { 279 Log.i(TAG, "Canceling installation"); 280 finish(); 281 } 282 }) 283 .setOnCancelListener(this) 284 .create(); 285 case DLG_INSTALL_ERROR : 286 // Guaranteed not to be null. will default to package name if not set by app 287 CharSequence appTitle1 = mPm.getApplicationLabel(mPkgInfo.applicationInfo); 288 String dlgText1 = getString(R.string.install_failed_msg, 289 appTitle1.toString()); 290 return new AlertDialog.Builder(this) 291 .setTitle(R.string.install_failed) 292 .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() { 293 public void onClick(DialogInterface dialog, int which) { 294 finish(); 295 } 296 }) 297 .setMessage(dlgText1) 298 .setOnCancelListener(this) 299 .create(); 300 case DLG_ALLOW_SOURCE: 301 CharSequence appTitle2 = mPm.getApplicationLabel(mSourceInfo); 302 String dlgText2 = getString(R.string.allow_source_dlg_text, 303 appTitle2.toString()); 304 return new AlertDialog.Builder(this) 305 .setTitle(R.string.allow_source_dlg_title) 306 .setMessage(dlgText2) 307 .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { 308 public void onClick(DialogInterface dialog, int which) { 309 setResult(RESULT_CANCELED); 310 finish(); 311 }}) 312 .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { 313 public void onClick(DialogInterface dialog, int which) { 314 SharedPreferences prefs = getSharedPreferences(PREFS_ALLOWED_SOURCES, 315 Context.MODE_PRIVATE); 316 prefs.edit().putBoolean(mSourceInfo.packageName, true).apply(); 317 startInstallConfirm(); 318 } 319 }) 320 .setOnCancelListener(this) 321 .create(); 322 } 323 return null; 324 } 325 326 private void launchSettingsAppAndFinish() { 327 // Create an intent to launch SettingsTwo activity 328 Intent launchSettingsIntent = new Intent(Settings.ACTION_SECURITY_SETTINGS); 329 launchSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 330 startActivity(launchSettingsIntent); 331 finish(); 332 } 333 334 private boolean isInstallingUnknownAppsAllowed() { 335 return Settings.Global.getInt(getContentResolver(), 336 Settings.Global.INSTALL_NON_MARKET_APPS, 0) > 0; 337 } 338 339 private boolean isInstallRequestFromUnknownSource(Intent intent) { 340 String callerPackage = getCallingPackage(); 341 if (callerPackage != null && intent.getBooleanExtra( 342 Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)) { 343 try { 344 mSourceInfo = mPm.getApplicationInfo(callerPackage, 0); 345 if (mSourceInfo != null) { 346 if ((mSourceInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) { 347 // Privileged apps are not considered an unknown source. 348 return false; 349 } 350 } 351 } catch (NameNotFoundException e) { 352 } 353 } 354 355 return true; 356 } 357 358 private boolean isVerifyAppsEnabled() { 359 return Settings.Global.getInt(getContentResolver(), 360 Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) > 0; 361 } 362 363 private boolean isAppVerifierInstalled() { 364 final PackageManager pm = getPackageManager(); 365 final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); 366 verification.setType(PACKAGE_MIME_TYPE); 367 verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 368 final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(verification, 0); 369 return (receivers.size() > 0) ? true : false; 370 } 371 372 private void initiateInstall() { 373 String pkgName = mPkgInfo.packageName; 374 // Check if there is already a package on the device with this name 375 // but it has been renamed to something else. 376 String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName }); 377 if (oldName != null && oldName.length > 0 && oldName[0] != null) { 378 pkgName = oldName[0]; 379 mPkgInfo.packageName = pkgName; 380 mPkgInfo.applicationInfo.packageName = pkgName; 381 } 382 // Check if package is already installed. display confirmation dialog if replacing pkg 383 try { 384 // This is a little convoluted because we want to get all uninstalled 385 // apps, but this may include apps with just data, and if it is just 386 // data we still want to count it as "installed". 387 mAppInfo = mPm.getApplicationInfo(pkgName, 388 PackageManager.GET_UNINSTALLED_PACKAGES); 389 if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) { 390 mAppInfo = null; 391 } 392 } catch (NameNotFoundException e) { 393 mAppInfo = null; 394 } 395 396 mInstallFlowAnalytics.setReplace(mAppInfo != null); 397 mInstallFlowAnalytics.setSystemApp( 398 (mAppInfo != null) && ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)); 399 400 startInstallConfirm(); 401 } 402 403 void setPmResult(int pmResult) { 404 Intent result = new Intent(); 405 result.putExtra(Intent.EXTRA_INSTALL_RESULT, pmResult); 406 setResult(pmResult == PackageManager.INSTALL_SUCCEEDED 407 ? RESULT_OK : RESULT_FIRST_USER, result); 408 } 409 410 @Override 411 protected void onCreate(Bundle icicle) { 412 super.onCreate(icicle); 413 414 // get intent information 415 final Intent intent = getIntent(); 416 mPackageURI = intent.getData(); 417 mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI); 418 mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER); 419 mPm = getPackageManager(); 420 421 boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent); 422 mInstallFlowAnalytics = new InstallFlowAnalytics(); 423 mInstallFlowAnalytics.setContext(this); 424 mInstallFlowAnalytics.setStartTimestampMillis(SystemClock.elapsedRealtime()); 425 mInstallFlowAnalytics.setInstallsFromUnknownSourcesPermitted( 426 isInstallingUnknownAppsAllowed()); 427 mInstallFlowAnalytics.setInstallRequestFromUnknownSource(requestFromUnknownSource); 428 mInstallFlowAnalytics.setVerifyAppsEnabled(isVerifyAppsEnabled()); 429 mInstallFlowAnalytics.setAppVerifierInstalled(isAppVerifierInstalled()); 430 mInstallFlowAnalytics.setPackageUri(mPackageURI.toString()); 431 432 final String scheme = mPackageURI.getScheme(); 433 if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) { 434 Log.w(TAG, "Unsupported scheme " + scheme); 435 setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI); 436 mInstallFlowAnalytics.setFlowFinished( 437 InstallFlowAnalytics.RESULT_FAILED_UNSUPPORTED_SCHEME); 438 finish(); 439 return; 440 } 441 442 final PackageUtil.AppSnippet as; 443 if ("package".equals(mPackageURI.getScheme())) { 444 mInstallFlowAnalytics.setFileUri(false); 445 try { 446 mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(), 447 PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES); 448 } catch (NameNotFoundException e) { 449 } 450 if (mPkgInfo == null) { 451 Log.w(TAG, "Requested package " + mPackageURI.getScheme() 452 + " not available. Discontinuing installation"); 453 showDialogInner(DLG_PACKAGE_ERROR); 454 setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); 455 mInstallFlowAnalytics.setPackageInfoObtained(); 456 mInstallFlowAnalytics.setFlowFinished( 457 InstallFlowAnalytics.RESULT_FAILED_PACKAGE_MISSING); 458 return; 459 } 460 as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo), 461 mPm.getApplicationIcon(mPkgInfo.applicationInfo)); 462 } else { 463 mInstallFlowAnalytics.setFileUri(true); 464 final File sourceFile = new File(mPackageURI.getPath()); 465 PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile); 466 467 // Check for parse errors 468 if (parsed == null) { 469 Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation"); 470 showDialogInner(DLG_PACKAGE_ERROR); 471 setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); 472 mInstallFlowAnalytics.setPackageInfoObtained(); 473 mInstallFlowAnalytics.setFlowFinished( 474 InstallFlowAnalytics.RESULT_FAILED_TO_GET_PACKAGE_INFO); 475 return; 476 } 477 mPkgInfo = PackageParser.generatePackageInfo(parsed, null, 478 PackageManager.GET_PERMISSIONS, 0, 0, null, 479 new PackageUserState()); 480 mPkgDigest = parsed.manifestDigest; 481 as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile); 482 } 483 mInstallFlowAnalytics.setPackageInfoObtained(); 484 485 //set view 486 setContentView(R.layout.install_start); 487 mInstallConfirm = findViewById(R.id.install_confirm_panel); 488 mInstallConfirm.setVisibility(View.INVISIBLE); 489 PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet); 490 491 mOriginatingUid = getOriginatingUid(intent); 492 493 // Block the install attempt on the Unknown Sources setting if necessary. 494 if ((requestFromUnknownSource) && (!isInstallingUnknownAppsAllowed())) { 495 //ask user to enable setting first 496 showDialogInner(DLG_UNKNOWN_APPS); 497 mInstallFlowAnalytics.setFlowFinished( 498 InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING); 499 return; 500 } 501 initiateInstall(); 502 } 503 504 /** Get the ApplicationInfo for the calling package, if available */ 505 private ApplicationInfo getSourceInfo() { 506 String callingPackage = getCallingPackage(); 507 if (callingPackage != null) { 508 try { 509 return mPm.getApplicationInfo(callingPackage, 0); 510 } catch (NameNotFoundException ex) { 511 // ignore 512 } 513 } 514 return null; 515 } 516 517 518 /** Get the originating uid if possible, or VerificationParams.NO_UID if not available */ 519 private int getOriginatingUid(Intent intent) { 520 // The originating uid from the intent. We only trust/use this if it comes from a 521 // system application 522 int uidFromIntent = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID, 523 VerificationParams.NO_UID); 524 525 // Get the source info from the calling package, if available. This will be the 526 // definitive calling package, but it only works if the intent was started using 527 // startActivityForResult, 528 ApplicationInfo sourceInfo = getSourceInfo(); 529 if (sourceInfo != null) { 530 if (uidFromIntent != VerificationParams.NO_UID && 531 (mSourceInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) { 532 return uidFromIntent; 533 534 } 535 // We either didn't get a uid in the intent, or we don't trust it. Use the 536 // uid of the calling package instead. 537 return sourceInfo.uid; 538 } 539 540 // We couldn't get the specific calling package. Let's get the uid instead 541 int callingUid; 542 try { 543 callingUid = ActivityManagerNative.getDefault() 544 .getLaunchedFromUid(getActivityToken()); 545 } catch (android.os.RemoteException ex) { 546 Log.w(TAG, "Could not determine the launching uid."); 547 // nothing else we can do 548 return VerificationParams.NO_UID; 549 } 550 551 // If we got a uid from the intent, we need to verify that the caller is a 552 // privileged system package before we use it 553 if (uidFromIntent != VerificationParams.NO_UID) { 554 String[] callingPackages = mPm.getPackagesForUid(callingUid); 555 if (callingPackages != null) { 556 for (String packageName: callingPackages) { 557 try { 558 ApplicationInfo applicationInfo = 559 mPm.getApplicationInfo(packageName, 0); 560 561 if ((applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) { 562 return uidFromIntent; 563 } 564 } catch (NameNotFoundException ex) { 565 // ignore it, and try the next package 566 } 567 } 568 } 569 } 570 // We either didn't get a uid from the intent, or we don't trust it. Use the 571 // calling uid instead. 572 return callingUid; 573 } 574 575 @Override 576 public void onBackPressed() { 577 mInstallFlowAnalytics.setFlowFinished( 578 InstallFlowAnalytics.RESULT_CANCELLED_BY_USER); 579 super.onBackPressed(); 580 } 581 582 // Generic handling when pressing back key 583 public void onCancel(DialogInterface dialog) { 584 finish(); 585 } 586 587 public void onClick(View v) { 588 if(v == mOk) { 589 if (mOkCanInstall || mScrollView == null) { 590 // Start subactivity to actually install the application 591 mInstallFlowAnalytics.setInstallButtonClicked(); 592 Intent newIntent = new Intent(); 593 newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, 594 mPkgInfo.applicationInfo); 595 newIntent.setData(mPackageURI); 596 newIntent.setClass(this, InstallAppProgress.class); 597 newIntent.putExtra(InstallAppProgress.EXTRA_MANIFEST_DIGEST, mPkgDigest); 598 newIntent.putExtra( 599 InstallAppProgress.EXTRA_INSTALL_FLOW_ANALYTICS, mInstallFlowAnalytics); 600 String installerPackageName = getIntent().getStringExtra( 601 Intent.EXTRA_INSTALLER_PACKAGE_NAME); 602 if (mOriginatingURI != null) { 603 newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI); 604 } 605 if (mReferrerURI != null) { 606 newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI); 607 } 608 if (mOriginatingUid != VerificationParams.NO_UID) { 609 newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid); 610 } 611 if (installerPackageName != null) { 612 newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, 613 installerPackageName); 614 } 615 if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) { 616 newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true); 617 newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); 618 } 619 if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI); 620 startActivity(newIntent); 621 finish(); 622 } else { 623 mScrollView.pageScroll(View.FOCUS_DOWN); 624 } 625 } else if(v == mCancel) { 626 // Cancel and finish 627 setResult(RESULT_CANCELED); 628 mInstallFlowAnalytics.setFlowFinished( 629 InstallFlowAnalytics.RESULT_CANCELLED_BY_USER); 630 finish(); 631 } 632 } 633 } 634