diff --git a/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBase.java b/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBase.java index fbded33fa6a..e25075f3453 100644 --- a/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBase.java +++ b/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBase.java @@ -14,7 +14,9 @@ package com.android.settings.applications.appinfo; +import android.app.role.RoleManager; import android.content.Context; +import android.content.Intent; import android.os.Bundle; import android.os.UserManager; import android.text.TextUtils; @@ -22,6 +24,7 @@ import android.text.TextUtils; import androidx.preference.Preference; import com.android.internal.logging.nano.MetricsProto; +import com.android.internal.util.CollectionUtils; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.applications.DefaultAppSettings; @@ -34,17 +37,31 @@ import com.android.settings.core.SubSettingLauncher; */ public abstract class DefaultAppShortcutPreferenceControllerBase extends BasePreferenceController { + private final String mRoleName; + protected final String mPackageName; + private final RoleManager mRoleManager; + + public DefaultAppShortcutPreferenceControllerBase(Context context, String preferenceKey, + String roleName, String packageName) { + super(context, preferenceKey); + + mRoleName = roleName; + mPackageName = packageName; + + mRoleManager = context.getSystemService(RoleManager.class); + } + + // TODO: STOPSHIP(b/110557011): Remove this once we have all default apps migrated. public DefaultAppShortcutPreferenceControllerBase(Context context, String preferenceKey, String packageName) { - super(context, preferenceKey); - mPackageName = packageName; + this(context, preferenceKey, null /* roleName */, packageName); } @Override public int getAvailabilityStatus() { - if (UserManager.get(mContext).isManagedProfile()) { + if (mContext.getSystemService(UserManager.class).isManagedProfile()) { return DISABLED_FOR_USER; } return hasAppCapability() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; @@ -52,13 +69,21 @@ public abstract class DefaultAppShortcutPreferenceControllerBase extends BasePre @Override public CharSequence getSummary() { - int summaryResId = isDefaultApp() ? R.string.yes : R.string.no; + final int summaryResId = isDefaultApp() ? R.string.yes : R.string.no; return mContext.getText(summaryResId); } @Override public boolean handlePreferenceTreeClick(Preference preference) { - if (TextUtils.equals(mPreferenceKey, preference.getKey())) { + if (!TextUtils.equals(mPreferenceKey, preference.getKey())) { + return false; + } + // TODO: STOPSHIP(b/110557011): Remove this check once we have all default apps migrated. + if (mRoleName != null) { + final Intent intent = new Intent(Intent.ACTION_MANAGE_DEFAULT_APP) + .putExtra(Intent.EXTRA_ROLE_NAME, mRoleName); + mContext.startActivity(intent); + } else { final Bundle bundle = new Bundle(); bundle.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, mPreferenceKey); new SubSettingLauncher(mContext) @@ -67,9 +92,8 @@ public abstract class DefaultAppShortcutPreferenceControllerBase extends BasePre .setTitleRes(R.string.configure_apps) .setSourceMetricsCategory(MetricsProto.MetricsEvent.VIEW_UNKNOWN) .launch(); - return true; } - return false; + return true; } /** @@ -77,13 +101,26 @@ public abstract class DefaultAppShortcutPreferenceControllerBase extends BasePre * * @return true if the app has the default app capability */ - protected abstract boolean hasAppCapability(); + protected boolean hasAppCapability() { + // TODO: STOPSHIP(b/110557011): Remove this check once we have all default apps migrated. + if (mRoleName != null) { + return mRoleManager.isRoleAvailable(mRoleName); + } + return false; + } /** * Check whether the app is the default app * * @return true if the app is the default app */ - protected abstract boolean isDefaultApp(); - + protected boolean isDefaultApp() { + // TODO: STOPSHIP(b/110557011): Remove this check once we have all default apps migrated. + if (mRoleName != null) { + final String packageName = CollectionUtils.firstOrNull(mRoleManager.getRoleHolders( + mRoleName)); + return TextUtils.equals(mPackageName, packageName); + } + return false; + } } diff --git a/src/com/android/settings/applications/appinfo/DefaultSmsShortcutPreferenceController.java b/src/com/android/settings/applications/appinfo/DefaultSmsShortcutPreferenceController.java index cf8b446b580..1b8393e50ed 100644 --- a/src/com/android/settings/applications/appinfo/DefaultSmsShortcutPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/DefaultSmsShortcutPreferenceController.java @@ -14,27 +14,15 @@ package com.android.settings.applications.appinfo; +import android.app.role.RoleManager; import android.content.Context; -import com.android.settings.applications.defaultapps.DefaultSmsPreferenceController; - public class DefaultSmsShortcutPreferenceController extends DefaultAppShortcutPreferenceControllerBase { private static final String KEY = "default_sms_app"; public DefaultSmsShortcutPreferenceController(Context context, String packageName) { - super(context, KEY, packageName); + super(context, KEY, RoleManager.ROLE_SMS, packageName); } - - @Override - protected boolean hasAppCapability() { - return DefaultSmsPreferenceController.hasSmsPreference(mPackageName, mContext); - } - - @Override - protected boolean isDefaultApp() { - return DefaultSmsPreferenceController.isSmsDefault(mPackageName, mContext); - } - } diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java index 529c0ee0bd1..719b7378cd2 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java @@ -18,11 +18,13 @@ package com.android.settings.applications.appinfo; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; import android.app.Activity; +import android.app.role.RoleManager; import android.content.Context; import android.content.Intent; import android.os.UserManager; @@ -42,108 +44,173 @@ import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowActivity; +import org.robolectric.shadows.ShadowApplication; import org.robolectric.shadows.ShadowUserManager; +import java.util.Collections; + @RunWith(RobolectricTestRunner.class) @Config(shadows = ShadowUserManager.class) public class DefaultAppShortcutPreferenceControllerBaseTest { - private ShadowUserManager mShadowUserManager; + private static final String TEST_PREFERENCE_KEY = "TestKey"; + private static final String TEST_ROLE_NAME = "TestRole"; + private static final String TEST_PACKAGE_NAME = "TestPackage"; + @Mock - private AppInfoDashboardFragment mFragment; + private RoleManager mRoleManager; @Mock private Preference mPreference; private Activity mActivity; - private TestPreferenceController mController; + private ShadowUserManager mShadowUserManager; + + private TestRolePreferenceController mController; + private TestLegacyPreferenceController mLegacyController; @Before public void setUp() { MockitoAnnotations.initMocks(this); + ShadowApplication.getInstance().setSystemService(Context.ROLE_SERVICE, mRoleManager); mActivity = Robolectric.setupActivity(Activity.class); mShadowUserManager = shadowOf(mActivity.getSystemService(UserManager.class)); - mController = new TestPreferenceController(mActivity, mFragment); - final String key = mController.getPreferenceKey(); - when(mPreference.getKey()).thenReturn(key); + mController = new TestRolePreferenceController(mActivity); + when(mPreference.getKey()).thenReturn(mController.getPreferenceKey()); + mLegacyController = new TestLegacyPreferenceController(mActivity); } @Test - public void getAvailabilityStatus_managedProfile_shouldReturnDisabled() { + public void getAvailabilityStatus_isManagedProfile_shouldReturnDisabled() { mShadowUserManager.setManagedProfile(true); - assertThat(mController.getAvailabilityStatus()) - .isEqualTo(DefaultAppShortcutPreferenceControllerBase.DISABLED_FOR_USER); + assertThat(mController.getAvailabilityStatus()).isEqualTo( + DefaultAppShortcutPreferenceControllerBase.DISABLED_FOR_USER); } @Test - public void getAvailabilityStatus_hasAppCapability_shouldReturnAvailable() { - mController.capable = true; + public void getAvailabilityStatus_roleIsAvailable_shouldReturnAvailable() { mShadowUserManager.setManagedProfile(false); + when(mRoleManager.isRoleAvailable(eq(TEST_ROLE_NAME))).thenReturn(true); - assertThat(mController.getAvailabilityStatus()) - .isEqualTo(DefaultAppShortcutPreferenceControllerBase.AVAILABLE); + assertThat(mController.getAvailabilityStatus()).isEqualTo( + DefaultAppShortcutPreferenceControllerBase.AVAILABLE); } @Test - public void getAvailabilityStatus_noAppCapability_shouldReturnDisabled() { - mController.capable = false; + public void getAvailabilityStatus_roleNotAvailable_shouldReturnDisabled() { mShadowUserManager.setManagedProfile(false); + when(mRoleManager.isRoleAvailable(eq(TEST_ROLE_NAME))).thenReturn(false); assertThat(mController.getAvailabilityStatus()).isEqualTo( DefaultAppShortcutPreferenceControllerBase.UNSUPPORTED_ON_DEVICE); } @Test - public void updateState_isDefaultApp_shouldSetSummaryToYes() { - mController.isDefault = true; + public void updateState_isRoleHolder_shouldSetSummaryToYes() { + when(mRoleManager.getRoleHolders(eq(TEST_ROLE_NAME))).thenReturn(Collections.singletonList( + TEST_PACKAGE_NAME)); + final CharSequence yesText = mActivity.getText(R.string.yes); mController.updateState(mPreference); - String yesString = mActivity.getString(R.string.yes); - verify(mPreference).setSummary(yesString); + verify(mPreference).setSummary(yesText); + } + + @Test + public void updateState_notRoleHoler_shouldSetSummaryToNo() { + when(mRoleManager.getRoleHolders(eq(TEST_ROLE_NAME))).thenReturn(Collections.emptyList()); + final CharSequence noText = mActivity.getText(R.string.no); + + mController.updateState(mPreference); + verify(mPreference).setSummary(noText); + } + + @Test + public void handlePreferenceTreeClick_shouldStartManageDefaultAppIntent() { + final ShadowActivity shadowActivity = shadowOf(mActivity); + + mController.handlePreferenceTreeClick(mPreference); + final Intent intent = shadowActivity.getNextStartedActivity(); + assertThat(intent).isNotNull(); + assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MANAGE_DEFAULT_APP); + assertThat(intent.getStringExtra(Intent.EXTRA_ROLE_NAME)).isEqualTo(TEST_ROLE_NAME); + } + + private class TestRolePreferenceController extends DefaultAppShortcutPreferenceControllerBase { + + private TestRolePreferenceController(Context context) { + super(context, TEST_PREFERENCE_KEY, TEST_ROLE_NAME, TEST_PACKAGE_NAME); + } + } + + // TODO: STOPSHIP(b/110557011): Remove following tests once we have all default apps migrated. + + @Test + public void getAvailabilityStatus_hasAppCapability_shouldReturnAvailable() { + mShadowUserManager.setManagedProfile(false); + mLegacyController.mHasAppCapability = true; + + assertThat(mLegacyController.getAvailabilityStatus()).isEqualTo( + DefaultAppShortcutPreferenceControllerBase.AVAILABLE); + } + + @Test + public void getAvailabilityStatus_noAppCapability_shouldReturnDisabled() { + mShadowUserManager.setManagedProfile(false); + mLegacyController.mHasAppCapability = false; + + assertThat(mLegacyController.getAvailabilityStatus()).isEqualTo( + DefaultAppShortcutPreferenceControllerBase.UNSUPPORTED_ON_DEVICE); + } + + @Test + public void updateState_isDefaultApp_shouldSetSummaryToYes() { + mLegacyController.mIsDefaultApp = true; + final CharSequence yesText = mActivity.getText(R.string.yes); + + mLegacyController.updateState(mPreference); + verify(mPreference).setSummary(yesText); } @Test public void updateState_notDefaultApp_shouldSetSummaryToNo() { - mController.isDefault = false; + mLegacyController.mIsDefaultApp = false; + final CharSequence noText = mActivity.getText(R.string.no); - mController.updateState(mPreference); - - String noString = mActivity.getString(R.string.no); - verify(mPreference).setSummary(noString); + mLegacyController.updateState(mPreference); + verify(mPreference).setSummary(noText); } @Test public void handlePreferenceTreeClick_shouldStartDefaultAppSettings() { final ShadowActivity shadowActivity = shadowOf(mActivity); - mController.handlePreferenceTreeClick(mPreference); - - final Intent nextIntent = shadowActivity.getNextStartedActivity(); - assertThat(nextIntent).isNotNull(); - assertThat(nextIntent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo( + mLegacyController.handlePreferenceTreeClick(mPreference); + final Intent intent = shadowActivity.getNextStartedActivity(); + assertThat(intent).isNotNull(); + assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo( DefaultAppSettings.class.getName()); - assertThat( - nextIntent.getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS).getString( - SettingsActivity.EXTRA_FRAGMENT_ARG_KEY)).isEqualTo("TestKey"); + assertThat(intent.getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS).getString( + SettingsActivity.EXTRA_FRAGMENT_ARG_KEY)).isEqualTo(TEST_PREFERENCE_KEY); } - private class TestPreferenceController extends DefaultAppShortcutPreferenceControllerBase { + private class TestLegacyPreferenceController + extends DefaultAppShortcutPreferenceControllerBase { - private boolean isDefault; - private boolean capable; + private boolean mIsDefaultApp; + private boolean mHasAppCapability; - private TestPreferenceController(Context context, AppInfoDashboardFragment parent) { - super(context, "TestKey", "TestPackage"); + private TestLegacyPreferenceController(Context context) { + super(context, TEST_PREFERENCE_KEY, TEST_PACKAGE_NAME); } @Override protected boolean hasAppCapability() { - return capable; + return mHasAppCapability; } @Override protected boolean isDefaultApp() { - return isDefault; + return mIsDefaultApp; } } } diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/DefaultSmsShortcutPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/DefaultSmsShortcutPreferenceControllerTest.java index 93582bf8776..6c8435fa29a 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/DefaultSmsShortcutPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/DefaultSmsShortcutPreferenceControllerTest.java @@ -18,79 +18,28 @@ package com.android.settings.applications.appinfo; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.content.pm.PackageManager; - -import com.android.settings.applications.defaultapps.DefaultSmsPreferenceController; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; @RunWith(RobolectricTestRunner.class) public class DefaultSmsShortcutPreferenceControllerTest { - @Mock - private PackageManager mPackageManager; + private static final String TEST_PACKAGE_NAME = "TestPackage"; + private static final String PREFERENCE_KEY = "default_sms_app"; - private Context mContext; private DefaultSmsShortcutPreferenceController mController; @Before public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = spy(RuntimeEnvironment.application); - when(mContext.getPackageManager()).thenReturn(mPackageManager); - mController = new DefaultSmsShortcutPreferenceController(mContext, "Package1"); + mController = new DefaultSmsShortcutPreferenceController(RuntimeEnvironment.application, + TEST_PACKAGE_NAME); } @Test public void getPreferenceKey_shouldReturnDefaultSms() { - assertThat(mController.getPreferenceKey()).isEqualTo("default_sms_app"); - } - - @Test - @Config(shadows = ShadowDefaultSmsPreferenceController.class) - public void hasAppCapability_hasSmsCapability_shouldReturnTrue() { - assertThat(mController.hasAppCapability()).isTrue(); - } - - @Test - public void hasAppCapability_noSmsCapability_shouldReturnFalse() { - assertThat(mController.hasAppCapability()).isFalse(); - } - - @Test - @Config(shadows = ShadowDefaultSmsPreferenceController.class) - public void isDefaultApp_isDefaultSms_shouldReturnTrue() { - assertThat(mController.isDefaultApp()).isTrue(); - } - - @Test - public void isDefaultApp_notDefaultSms_shouldReturnFalse() { - assertThat(mController.isDefaultApp()).isFalse(); - } - - @Implements(DefaultSmsPreferenceController.class) - public static class ShadowDefaultSmsPreferenceController { - @Implementation - protected static boolean hasSmsPreference(String pkg, Context context) { - return true; - } - - @Implementation - protected static boolean isSmsDefault(String pkg, Context context) { - return true; - } + assertThat(mController.getPreferenceKey()).isEqualTo(PREFERENCE_KEY); } }