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.annotation.Nullable; 20 import android.app.Activity; 21 import android.app.AlertDialog; 22 import android.app.Dialog; 23 import android.app.DialogFragment; 24 import android.content.Context; 25 import android.content.DialogInterface; 26 import android.content.Intent; 27 import android.content.pm.ApplicationInfo; 28 import android.content.pm.PackageInstaller; 29 import android.content.pm.PackageManager; 30 import android.net.Uri; 31 import android.os.Bundle; 32 import android.util.Log; 33 import android.view.View; 34 35 import com.android.internal.app.AlertActivity; 36 37 import java.io.File; 38 39 /** 40 * Installation failed: Return status code to the caller or display failure UI to user 41 */ 42 public class InstallFailed extends AlertActivity { 43 private static final String LOG_TAG = InstallFailed.class.getSimpleName(); 44 45 /** Label of the app that failed to install */ 46 private CharSequence mLabel; 47 48 /** 49 * Unhide the appropriate label for the statusCode. 50 * 51 * @param statusCode The status code from the package installer. 52 */ setExplanationFromErrorCode(int statusCode)53 private void setExplanationFromErrorCode(int statusCode) { 54 Log.d(LOG_TAG, "Installation status code: " + statusCode); 55 56 View viewToEnable; 57 switch (statusCode) { 58 case PackageInstaller.STATUS_FAILURE_BLOCKED: 59 viewToEnable = requireViewById(R.id.install_failed_blocked); 60 break; 61 case PackageInstaller.STATUS_FAILURE_CONFLICT: 62 viewToEnable = requireViewById(R.id.install_failed_conflict); 63 break; 64 case PackageInstaller.STATUS_FAILURE_INCOMPATIBLE: 65 viewToEnable = requireViewById(R.id.install_failed_incompatible); 66 break; 67 case PackageInstaller.STATUS_FAILURE_INVALID: 68 viewToEnable = requireViewById(R.id.install_failed_invalid_apk); 69 break; 70 default: 71 viewToEnable = requireViewById(R.id.install_failed); 72 break; 73 } 74 75 viewToEnable.setVisibility(View.VISIBLE); 76 } 77 78 @Override onCreate(@ullable Bundle savedInstanceState)79 protected void onCreate(@Nullable Bundle savedInstanceState) { 80 super.onCreate(savedInstanceState); 81 82 int statusCode = getIntent().getIntExtra(PackageInstaller.EXTRA_STATUS, 83 PackageInstaller.STATUS_FAILURE); 84 85 if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) { 86 int legacyStatus = getIntent().getIntExtra(PackageInstaller.EXTRA_LEGACY_STATUS, 87 PackageManager.INSTALL_FAILED_INTERNAL_ERROR); 88 89 // Return result if requested 90 Intent result = new Intent(); 91 result.putExtra(Intent.EXTRA_INSTALL_RESULT, legacyStatus); 92 setResult(Activity.RESULT_FIRST_USER, result); 93 finish(); 94 } else { 95 Intent intent = getIntent(); 96 ApplicationInfo appInfo = intent 97 .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); 98 Uri packageURI = intent.getData(); 99 100 // Set header icon and title 101 PackageUtil.AppSnippet as; 102 PackageManager pm = getPackageManager(); 103 104 if ("package".equals(packageURI.getScheme())) { 105 as = new PackageUtil.AppSnippet(pm.getApplicationLabel(appInfo), 106 pm.getApplicationIcon(appInfo)); 107 } else { 108 final File sourceFile = new File(packageURI.getPath()); 109 as = PackageUtil.getAppSnippet(this, appInfo, sourceFile); 110 } 111 112 // Store label for dialog 113 mLabel = as.label; 114 115 mAlert.setIcon(as.icon); 116 mAlert.setTitle(as.label); 117 mAlert.setView(R.layout.install_content_view); 118 mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.done), 119 (ignored, ignored2) -> finish(), null); 120 setupAlert(); 121 122 // Show out of space dialog if needed 123 if (statusCode == PackageInstaller.STATUS_FAILURE_STORAGE) { 124 (new OutOfSpaceDialog()).show(getFragmentManager(), "outofspace"); 125 } 126 127 // Get status messages 128 setExplanationFromErrorCode(statusCode); 129 } 130 } 131 132 /** 133 * Dialog shown when we ran out of space during installation. This contains a link to the 134 * "manage applications" settings page. 135 */ 136 public static class OutOfSpaceDialog extends DialogFragment { 137 private InstallFailed mActivity; 138 139 @Override onAttach(Context context)140 public void onAttach(Context context) { 141 super.onAttach(context); 142 143 mActivity = (InstallFailed) context; 144 } 145 146 @Override onCreateDialog(Bundle savedInstanceState)147 public Dialog onCreateDialog(Bundle savedInstanceState) { 148 return new AlertDialog.Builder(mActivity) 149 .setTitle(R.string.out_of_space_dlg_title) 150 .setMessage(getString(R.string.out_of_space_dlg_text, mActivity.mLabel)) 151 .setPositiveButton(R.string.manage_applications, (dialog, which) -> { 152 // launch manage applications 153 Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE"); 154 startActivity(intent); 155 mActivity.finish(); 156 }) 157 .setNegativeButton(R.string.cancel, (dialog, which) -> mActivity.finish()) 158 .create(); 159 } 160 161 @Override onCancel(DialogInterface dialog)162 public void onCancel(DialogInterface dialog) { 163 super.onCancel(dialog); 164 165 mActivity.finish(); 166 } 167 } 168 } 169