Add CTS to enforce result behaviour of CPA startActivity

Enforce that CrossProfileApps#startActivity successfully passes results
back to the passed-in calling activity.

Bug: 174506563
Fixes: 171957840
Test: atest com.android.cts.devicepolicy.CrossProfileAppsHostSideTest#testStartActivityIntent_crossProfile_returnsResult
Change-Id: I4502048974e3dac107180488ac5870b9b7fd7786
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/AndroidManifest.xml b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/AndroidManifest.xml
index ae3ff05..474df01 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/AndroidManifest.xml
@@ -53,7 +53,14 @@
             </intent-filter>
         </activity>
 
-        <activity android:name=".CrossProfileSameTaskLauncherActivity" android:exported="true"/>
+        <activity android:name=".CrossProfileSameTaskLauncherActivity"
+             android:exported="true"/>
+
+        <activity android:name=".CrossProfileResultCheckerActivity"
+             android:exported="true"/>
+
+        <activity android:name=".CrossProfileResultReturnerActivity"
+             android:exported="true"/>
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/res/layout/cross_profile_result_checker.xml b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/res/layout/cross_profile_result_checker.xml
new file mode 100644
index 0000000..5689f32
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/res/layout/cross_profile_result_checker.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/cross_profile_result_checker_result"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+    />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java
index 6b41018..7332521 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java
@@ -19,6 +19,8 @@
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static junit.framework.Assert.assertNotNull;
 
 import static org.junit.Assert.assertEquals;
@@ -276,6 +278,23 @@
         }
     }
 
+    @Test
+    public void testStartActivityIntent_crossProfile_returnsResult() throws Exception {
+        try {
+            mContext.startActivity(new Intent()
+                    .setComponent(CrossProfileResultCheckerActivity.buildComponentName(mContext))
+                    .putExtra(CrossProfileResultCheckerActivity.TARGET_USER_EXTRA, mTargetUser));
+
+            final UiObject2 textView = mDevice.wait(
+                    Until.findObject(
+                            By.text(CrossProfileResultCheckerActivity.SUCCESS_MESSAGE)),
+                    TIMEOUT_WAIT_UI);
+            assertThat(textView).isNotNull();
+        } catch (Exception e) {
+            fail("unable to start cross-profile activity to obtain a returned result: " + e);
+        }
+    }
+
     /**
      * Calls {@link CrossProfileApps#startActivity(Intent, UserHandle, Activity)}. This can then be
      * used by host-side tests.
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileResultCheckerActivity.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileResultCheckerActivity.java
new file mode 100644
index 0000000..49f2d9b
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileResultCheckerActivity.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.crossprofileappstest;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.CrossProfileApps;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+/**
+ * An activity that launches {@link CrossProfileResultReturnerActivity} for result, then displays
+ * the string {@link #SUCCESS_MESSAGE} if successful.
+ *
+ * <p>Must be launched with intent extra {@link #TARGET_USER_EXTRA} with the numeric target user ID.
+ */
+public class CrossProfileResultCheckerActivity extends Activity {
+    static final String SUCCESS_MESSAGE = "Successfully received cross-profile result.";
+    static final String TARGET_USER_EXTRA = "TARGET_USER";
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final Intent intent = getIntent();
+        if (!intent.hasExtra(TARGET_USER_EXTRA)) {
+            throw new IllegalStateException(
+                    "CrossProfileResultCheckerActivity started without " + TARGET_USER_EXTRA);
+        }
+        setContentView(R.layout.cross_profile_result_checker);
+        final Intent resultReturnerIntent =
+                new Intent().setComponent(
+                        CrossProfileResultReturnerActivity.buildComponentName(this));
+        final UserHandle targetUser = intent.getParcelableExtra(TARGET_USER_EXTRA);
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+                getSystemService(CrossProfileApps.class),
+                crossProfileApps -> crossProfileApps.startActivity(
+                        resultReturnerIntent, targetUser, this));
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (resultCode != CrossProfileResultReturnerActivity.RESULT_CODE) {
+            throw new IllegalStateException("Unknown result code: " + resultCode);
+        }
+        final TextView textView = findViewById(R.id.cross_profile_result_checker_result);
+        textView.setText(SUCCESS_MESSAGE);
+    }
+
+    static ComponentName buildComponentName(Context context) {
+        return new ComponentName(context, CrossProfileResultCheckerActivity.class);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileResultReturnerActivity.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileResultReturnerActivity.java
new file mode 100644
index 0000000..8898e91
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileResultReturnerActivity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.crossprofileappstest;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+
+/** An activity that sets the result as {@link #RESULT_CODE} then finishes. */
+public class CrossProfileResultReturnerActivity extends Activity {
+    static final int RESULT_CODE = 998;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        setResult(RESULT_CODE);
+        finish();
+    }
+
+    static ComponentName buildComponentName(Context context) {
+        return new ComponentName(context, CrossProfileResultReturnerActivity.class);
+    }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java
index 345c91e..ddaf864 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java
@@ -168,6 +168,8 @@
     @LargeTest
     @Test
     public void testStartActivityIntent_sameTaskByDefault() throws Exception {
+        // TODO(b/171957840): replace with device-side test using an inter-process communication
+        //  library.
         if (!mHasManagedUserFeature) {
             return;
         }
@@ -194,6 +196,21 @@
 
     @LargeTest
     @Test
+    public void testStartActivityIntent_crossProfile_returnsResult() throws Exception {
+        // TODO(b/171957840): replace with device-side test using an inter-process communication
+        //  library.
+        if (!mHasManagedUserFeature) {
+            return;
+        }
+        verifyCrossProfileAppsApi(
+                mProfileId,
+                mPrimaryUserId,
+                START_ACTIVITY_TEST_CLASS,
+                "testStartActivityIntent_crossProfile_returnsResult");
+    }
+
+    @LargeTest
+    @Test
     public void testPrimaryUserToSecondaryUser() throws Exception {
         if (!mCanTestMultiUser) {
             return;