Changed default assistant picker to verify if can intent to an activity.

Updated assistant picker to use startActivityForResult intead of
startActivity because Google Assistant requires this.

Bug: 145236084
Test: Manual, robolectric
Change-Id: Id1b0e5d270ac5cedc380edeb9bfefbff566b06d3
diff --git a/src/com/android/car/settings/applications/defaultapps/DefaultAppsPickerEntryBasePreferenceController.java b/src/com/android/car/settings/applications/defaultapps/DefaultAppsPickerEntryBasePreferenceController.java
index e64df67..f61a16f 100644
--- a/src/com/android/car/settings/applications/defaultapps/DefaultAppsPickerEntryBasePreferenceController.java
+++ b/src/com/android/car/settings/applications/defaultapps/DefaultAppsPickerEntryBasePreferenceController.java
@@ -19,6 +19,7 @@
 import android.car.drivingstate.CarUxRestrictions;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 
 import androidx.annotation.Nullable;
 
@@ -48,9 +49,25 @@
         super.updateState(preference);
 
         Intent intent = getSettingIntent(getCurrentDefaultAppInfo());
-        preference.showAction(intent != null);
+        boolean isSafeIntent = false;
         if (intent != null) {
-            preference.setOnButtonClickListener(p -> getContext().startActivity(intent));
+            ActivityInfo info = intent.resolveActivityInfo(
+                    getContext().getPackageManager(), intent.getFlags());
+            // If activity exists and is visible to Car Settings, allow intenting to the activity.
+            if (info != null && info.exported) {
+                isSafeIntent = true;
+            }
+        }
+        preference.showAction(isSafeIntent);
+        if (isSafeIntent) {
+            // Use startActivityForResult because some apps need to check the identity of the
+            // caller.
+            preference.setOnButtonClickListener(p -> getContext().startActivityForResult(
+                    getContext().getBasePackageName(),
+                    intent,
+                    /* requestCode= */ 0,
+                    /* options= */ null
+            ));
         }
     }
 
diff --git a/tests/robotests/src/com/android/car/settings/applications/defaultapps/DefaultAppsPickerEntryBasePreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/applications/defaultapps/DefaultAppsPickerEntryBasePreferenceControllerTest.java
index 8119755..55179a7 100644
--- a/tests/robotests/src/com/android/car/settings/applications/defaultapps/DefaultAppsPickerEntryBasePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/car/settings/applications/defaultapps/DefaultAppsPickerEntryBasePreferenceControllerTest.java
@@ -18,11 +18,19 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 
 import android.car.drivingstate.CarUxRestrictions;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
 import android.provider.Settings;
 
 import androidx.annotation.Nullable;
@@ -38,7 +46,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.Shadows;
 
 @RunWith(CarSettingsRobolectricTestRunner.class)
 public class DefaultAppsPickerEntryBasePreferenceControllerTest {
@@ -83,7 +91,7 @@
 
     @Before
     public void setUp() {
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
         mButtonPreference = new ButtonPreference(mContext);
         mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
                 TestDefaultAppsPickerEntryBasePreferenceController.class, mButtonPreference);
@@ -91,15 +99,6 @@
     }
 
     @Test
-    public void refreshUi_hasSettingIntent_actionButtonIsVisible() {
-        mController.setSettingIntent(TEST_INTENT);
-        mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
-        mController.refreshUi();
-
-        assertThat(mButtonPreference.isActionShown()).isTrue();
-    }
-
-    @Test
     public void refreshUi_hasNoSettingIntent_actionButtonIsNotVisible() {
         mController.setSettingIntent(null);
         mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
@@ -109,12 +108,53 @@
     }
 
     @Test
+    public void refreshUi_hasSettingIntentButNoResolvableActivity_actionButtonIsNotVisible() {
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = null;
+        Shadows.shadowOf(mContext.getPackageManager()).addResolveInfoForIntent(
+                TEST_INTENT, resolveInfo);
+        mController.setSettingIntent(TEST_INTENT);
+        mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
+        mController.refreshUi();
+
+        assertThat(mButtonPreference.isActionShown()).isFalse();
+    }
+
+    @Test
+    public void refreshUi_hasSettingIntentButNoVisibleActivity_actionButtonIsNotVisible() {
+        ActivityInfo activityInfo = new ActivityInfo();
+        activityInfo.exported = false;
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = activityInfo;
+        Shadows.shadowOf(mContext.getPackageManager()).addResolveInfoForIntent(
+                TEST_INTENT, resolveInfo);
+        mController.setSettingIntent(TEST_INTENT);
+        mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
+        mController.refreshUi();
+
+        assertThat(mButtonPreference.isActionShown()).isFalse();
+    }
+
+    @Test
+    public void refreshUi_hasSettingIntent_actionButtonIsVisible() {
+        mController.setSettingIntent(TEST_INTENT);
+        mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
+        mController.refreshUi();
+
+        assertThat(mButtonPreference.isActionShown()).isTrue();
+    }
+
+    @Test
     public void performButtonClick_launchesIntent() {
+        // Need to spy context because RuntimeEnvironment.application is not an Activity-based
+        // context, and so throws RuntimeException when we call startActivityForResult.
+        doNothing().when(mContext).startActivityForResult(
+                any(String.class), any(Intent.class), eq(0), isNull());
         mController.setSettingIntent(TEST_INTENT);
         mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
         mButtonPreference.performButtonClick();
 
-        Intent actual = ShadowApplication.getInstance().getNextStartedActivity();
-        assertThat(actual.getAction()).isEqualTo(TEST_INTENT.getAction());
+        verify(mContext).startActivityForResult(
+                "android", TEST_INTENT, 0, null);
     }
 }