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);
}
}