Add manifest attribute for display across devices

Allow an activity to opt in or out from being streamed to a remote
device by the application manifest.

Also add meta-data support of apps that targeting on previous SDK.

Bug: 201712607
Test: Manual
Change-Id: If39442d19316653cacae4c060f9f374958eb92a5
diff --git a/core/api/current.txt b/core/api/current.txt
index 8e3faaa..ba4c4d3 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -411,6 +411,7 @@
     field public static final int calendarViewShown = 16843596; // 0x101034c
     field public static final int calendarViewStyle = 16843613; // 0x101035d
     field public static final int canControlMagnification = 16844039; // 0x1010507
+    field public static final int canDisplayOnRemoteDevices;
     field public static final int canPauseRecording = 16844314; // 0x101061a
     field public static final int canPerformGestures = 16844045; // 0x101050d
     field public static final int canRecord = 16844060; // 0x101051c
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index cbb5c2b..78852b4 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -447,6 +447,12 @@
      * @see android.app.Activity#setVrModeEnabled(boolean, ComponentName)
      */
     public static final int FLAG_ENABLE_VR_MODE = 0x8000;
+    /**
+     * Bit in {@link #flags} indicating if the activity can be displayed on a remote device.
+     * Corresponds to {@link android.R.attr#canDisplayOnRemoteDevices}
+     * @hide
+     */
+    public static final int FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES = 0x10000;
 
     /**
      * Bit in {@link #flags} indicating if the activity is always focusable regardless of if it is
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index d19186e..1204d74 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -52,7 +52,6 @@
 import android.content.pm.parsing.component.ComponentMutateUtils;
 import android.content.pm.parsing.component.ComponentParseUtils;
 import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedActivityImpl;
 import android.content.pm.parsing.component.ParsedActivityUtils;
 import android.content.pm.parsing.component.ParsedAttribution;
 import android.content.pm.parsing.component.ParsedAttributionUtils;
@@ -194,6 +193,8 @@
 
     public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
     public static final String METADATA_SUPPORTS_SIZE_CHANGES = "android.supports_size_changes";
+    public static final String METADATA_CAN_DISPLAY_ON_REMOTE_DEVICES =
+            "android.can_display_on_remote_devices";
     public static final String METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY =
             "android.activity_window_layout_affinity";
     public static final String METADATA_ACTIVITY_LAUNCH_MODE = "android.activity.launch_mode";
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index 45241b0..2ddf923 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -420,6 +420,21 @@
             }
         }
 
+        if (!isAlias) {
+            // Default allow the activity to be displayed on a remote device unless it explicitly
+            // set to false.
+            boolean canDisplayOnRemoteDevices = array.getBoolean(
+                    R.styleable.AndroidManifestActivity_canDisplayOnRemoteDevices, true);
+            if (activity.getMetaData() != null && !activity.getMetaData().getBoolean(
+                    ParsingPackageUtils.METADATA_CAN_DISPLAY_ON_REMOTE_DEVICES, true)) {
+                canDisplayOnRemoteDevices = false;
+            }
+            if (canDisplayOnRemoteDevices) {
+                activity.setFlags(activity.getFlags()
+                        | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES);
+            }
+        }
+
         ParseResult<ActivityInfo.WindowLayout> layoutResult =
                 resolveActivityWindowLayout(activity, input);
         if (layoutResult.isError()) {
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 755938e..7805d46 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2953,6 +2953,9 @@
              usually TVs.
              <p>Requires permission {@code android.permission.DISABLE_SYSTEM_SOUND_EFFECTS}. -->
         <attr name="playHomeTransitionSound" format="boolean"/>
+        <!-- Indicates whether the activity can be displayed on a remote device which may or
+             may not be running Android. -->
+        <attr name="canDisplayOnRemoteDevices" format="boolean"/>
     </declare-styleable>
 
     <!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ed49fe4..fcff778 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3303,6 +3303,7 @@
     <public name="sharedUserMaxSdkVersion" />
     <public name="requiredSplitTypes" />
     <public name="splitTypes" />
+    <public name="canDisplayOnRemoteDevices" />
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01de0000">