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.util.Log; 32 import android.view.View; 33 34 import androidx.annotation.Nullable; 35 36 /** 37 * Installation failed: Return status code to the caller or display failure UI to user 38 */ 39 public class InstallFailed extends AlertActivity { 40 private static final String LOG_TAG = InstallFailed.class.getSimpleName(); 41 42 /** Label of the app that failed to install */ 43 private CharSequence mLabel; 44 45 /** 46 * Unhide the appropriate label for the statusCode. 47 * 48 * @param statusCode The status code from the package installer. 49 */ setExplanationFromErrorCode(int statusCode)50 private void setExplanationFromErrorCode(int statusCode) { 51 Log.d(LOG_TAG, "Installation status code: " + statusCode); 52 53 View viewToEnable; 54 switch (statusCode) { 55 case PackageInstaller.STATUS_FAILURE_BLOCKED: 56 viewToEnable = requireViewById(R.id.install_failed_blocked); 57 break; 58 case PackageInstaller.STATUS_FAILURE_CONFLICT: 59 viewToEnable = requireViewById(R.id.install_failed_conflict); 60 break; 61 case PackageInstaller.STATUS_FAILURE_INCOMPATIBLE: 62 viewToEnable = requireViewById(R.id.install_failed_incompatible); 63 break; 64 case PackageInstaller.STATUS_FAILURE_INVALID: 65 viewToEnable = requireViewById(R.id.install_failed_invalid_apk); 66 break; 67 default: 68 viewToEnable = requireViewById(R.id.install_failed); 69 break; 70 } 71 72 viewToEnable.setVisibility(View.VISIBLE); 73 } 74 75 @Override onCreate(@ullable Bundle savedInstanceState)76 protected void onCreate(@Nullable Bundle savedInstanceState) { 77 super.onCreate(savedInstanceState); 78 79 setFinishOnTouchOutside(true); 80 81 int statusCode = getIntent().getIntExtra(PackageInstaller.EXTRA_STATUS, 82 PackageInstaller.STATUS_FAILURE); 83 84 if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) { 85 int legacyStatus = getIntent().getIntExtra(PackageInstaller.EXTRA_LEGACY_STATUS, 86 PackageManager.INSTALL_FAILED_INTERNAL_ERROR); 87 88 // Return result if requested 89 Intent result = new Intent(); 90 result.putExtra(Intent.EXTRA_INSTALL_RESULT, legacyStatus); 91 setResult(Activity.RESULT_FIRST_USER, result); 92 finish(); 93 } else { 94 Intent intent = getIntent(); 95 ApplicationInfo appInfo = intent 96 .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); 97 Uri packageURI = intent.getData(); 98 99 // Set header icon and title 100 PackageUtil.AppSnippet as; 101 PackageManager pm = getPackageManager(); 102 as = intent.getParcelableExtra(PackageInstallerActivity.EXTRA_APP_SNIPPET, 103 PackageUtil.AppSnippet.class); 104 105 // Store label for dialog 106 mLabel = as.label; 107 108 mAlert.setIcon(as.icon); 109 mAlert.setTitle(as.label); 110 mAlert.setView(R.layout.install_content_view); 111 mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.done), 112 (ignored, ignored2) -> finish(), null); 113 setupAlert(); 114 115 // Show out of space dialog if needed 116 if (statusCode == PackageInstaller.STATUS_FAILURE_STORAGE) { 117 (new OutOfSpaceDialog()).show(getFragmentManager(), "outofspace"); 118 } 119 120 // Get status messages 121 setExplanationFromErrorCode(statusCode); 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