Allow applications to define failure handlers

Fixes: 37956764
Test: Manual
Test: Create a test app with no handler, see it's not passed to the installer
Test: Create a test app with a handler, see it's passed to the installer
Test: Create a test app with multiple handlers, see one is passed to the installer
Test: Create a test app with a handler defined in a split, see it's not passed to the installer
Change-Id: Idfc3648154afca7ec300019d9695417274118d6f
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index daeb987..9623da3 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1535,6 +1535,22 @@
     public static final String ACTION_INSTALL_PACKAGE = "android.intent.action.INSTALL_PACKAGE";
 
     /**
+     * Activity Action: Activity to handle split installation failures.
+     * <p>Splits may be installed dynamically. This happens when an Activity is launched,
+     * but the split that contains the application isn't installed. When a split is
+     * installed in this manner, the containing package usually doesn't know this is
+     * happening. However, if an error occurs during installation, the containing
+     * package can define a single activity handling this action to deal with such
+     * failures.
+     * <p>The activity handling this action must be in the base package.
+     * <p>
+     * Input: {@link #EXTRA_INTENT} the original intent that started split installation.
+     * {@link #EXTRA_SPLIT_NAME} the name of the split that failed to be installed.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_INSTALL_FAILURE = "android.intent.action.INSTALL_FAILURE";
+
+    /**
      * @hide
      * @deprecated Do not use. This will go away.
      *     Replace with {@link #ACTION_INSTALL_INSTANT_APP_PACKAGE}.
@@ -1823,9 +1839,7 @@
      * <p>
      * Type: String
      * </p>
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME";
 
     /**
diff --git a/core/java/android/content/pm/AuxiliaryResolveInfo.java b/core/java/android/content/pm/AuxiliaryResolveInfo.java
index 323733c..067363d 100644
--- a/core/java/android/content/pm/AuxiliaryResolveInfo.java
+++ b/core/java/android/content/pm/AuxiliaryResolveInfo.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
 
@@ -35,6 +36,8 @@
     public final InstantAppResolveInfo resolveInfo;
     /** The resolved package. Copied from {@link #resolveInfo}. */
     public final String packageName;
+    /** The activity to launch if there's an installation failure. */
+    public final ComponentName installFailureActivity;
     /** The resolve split. Copied from the matched filter in {@link #resolveInfo}. */
     public final String splitName;
     /** Whether or not instant resolution needs the second phase */
@@ -61,15 +64,18 @@
         this.needsPhaseTwo = needsPhase2;
         this.versionCode = resolveInfo.getVersionCode();
         this.failureIntent = failureIntent;
+        this.installFailureActivity = null;
     }
 
     /** Create a response for installing a split on demand. */
     public AuxiliaryResolveInfo(@NonNull String packageName,
             @Nullable String splitName,
+            @Nullable ComponentName failureActivity,
             int versionCode,
             @Nullable Intent failureIntent) {
         super();
         this.packageName = packageName;
+        this.installFailureActivity = failureActivity;
         this.splitName = splitName;
         this.versionCode = versionCode;
         this.resolveInfo = null;