1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 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.app.DialogFragment; 23 import android.content.Context; 24 import android.content.DialogInterface; 25 import android.content.Intent; 26 import android.content.pm.ApplicationInfo; 27 import android.content.pm.PackageInstaller; 28 import android.content.pm.PackageManager; 29 import android.net.Uri; 30 import android.os.Bundle; 31 import android.support.annotation.Nullable; 32 import android.util.Log; 33 import android.widget.TextView; 34 35 import java.io.File; 36 37 /** 38 * Installation failed: Return status code to the caller or display failure UI to user 39 */ 40 public class InstallFailed extends Activity { 41 private static final String LOG_TAG = InstallFailed.class.getSimpleName(); 42 43 /** Label of the app that failed to install */ 44 private CharSequence mLabel; 45 46 /** 47 * Convert an package installer status code into the user friendly label. 48 * 49 * @param statusCode The status code from the package installer. 50 * 51 * @return The user friendly label for the status code 52 */ getExplanationFromErrorCode(int statusCode)53 private int getExplanationFromErrorCode(int statusCode) { 54 Log.d(LOG_TAG, "Installation status code: " + statusCode); 55 56 switch (statusCode) { 57 case PackageInstaller.STATUS_FAILURE_BLOCKED: 58 return R.string.install_failed_blocked; 59 case PackageInstaller.STATUS_FAILURE_CONFLICT: 60 return R.string.install_failed_conflict; 61 case PackageInstaller.STATUS_FAILURE_INCOMPATIBLE: 62 return R.string.install_failed_incompatible; 63 case PackageInstaller.STATUS_FAILURE_INVALID: 64 return R.string.install_failed_invalid_apk; 65 default: 66 return R.string.install_failed; 67 } 68 } 69 70 @Override onCreate(@ullable Bundle savedInstanceState)71 protected void onCreate(@Nullable Bundle savedInstanceState) { 72 super.onCreate(savedInstanceState); 73 74 int statusCode = getIntent().getIntExtra(PackageInstaller.EXTRA_STATUS, 75 PackageInstaller.STATUS_FAILURE); 76 77 if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) { 78 int legacyStatus = getIntent().getIntExtra(PackageInstaller.EXTRA_LEGACY_STATUS, 79 PackageManager.INSTALL_FAILED_INTERNAL_ERROR); 80 81 // Return result if requested 82 Intent result = new Intent(); 83 result.putExtra(Intent.EXTRA_INSTALL_RESULT, legacyStatus); 84 setResult(Activity.RESULT_FIRST_USER, result); 85 finish(); 86 } else { 87 Intent intent = getIntent(); 88 ApplicationInfo appInfo = intent 89 .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); 90 Uri packageURI = intent.getData(); 91 92 setContentView(R.layout.install_failed); 93 94 // Set header icon and title 95 PackageUtil.AppSnippet as; 96 PackageManager pm = getPackageManager(); 97 98 if ("package".equals(packageURI.getScheme())) { 99 as = new PackageUtil.AppSnippet(pm.getApplicationLabel(appInfo), 100 pm.getApplicationIcon(appInfo)); 101 } else { 102 final File sourceFile = new File(packageURI.getPath()); 103 as = PackageUtil.getAppSnippet(this, appInfo, sourceFile); 104 } 105 106 // Store label for dialog 107 mLabel = as.label; 108 109 PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet); 110 111 // Show out of space dialog if needed 112 if (statusCode == PackageInstaller.STATUS_FAILURE_STORAGE) { 113 (new OutOfSpaceDialog()).show(getFragmentManager(), "outofspace"); 114 } 115 116 // Get status messages 117 ((TextView) findViewById(R.id.simple_status)).setText( 118 getExplanationFromErrorCode(statusCode)); 119 120 // Set up "done" button 121 findViewById(R.id.done_button).setOnClickListener(view -> finish()); 122 } 123 } 124 125 /** 126 * Dialog shown when we ran out of space during installation. This contains a link to the 127 * "manage applications" settings page. 128 */ 129 public static class OutOfSpaceDialog extends DialogFragment { 130 private InstallFailed mActivity; 131 132 @Override onAttach(Context context)133 public void onAttach(Context context) { 134 super.onAttach(context); 135 136 mActivity = (InstallFailed) context; 137 } 138 139 @Override onCreateDialog(Bundle savedInstanceState)140 public Dialog onCreateDialog(Bundle savedInstanceState) { 141 return new AlertDialog.Builder(mActivity) 142 .setTitle(R.string.out_of_space_dlg_title) 143 .setMessage(getString(R.string.out_of_space_dlg_text, mActivity.mLabel)) 144 .setPositiveButton(R.string.manage_applications, (dialog, which) -> { 145 // launch manage applications 146 Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE"); 147 startActivity(intent); 148 mActivity.finish(); 149 }) 150 .setNegativeButton(R.string.cancel, (dialog, which) -> mActivity.finish()) 151 .create(); 152 } 153 154 @Override onCancel(DialogInterface dialog)155 public void onCancel(DialogInterface dialog) { 156 super.onCancel(dialog); 157 158 mActivity.finish(); 159 } 160 } 161 } 162