Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8541c6c4 authored by Joanne Chung's avatar Joanne Chung Committed by Android (Google) Code Review
Browse files

Merge "Allow uninstallation of current home app" into main

parents 29c3b875 b3e21795
Loading
Loading
Loading
Loading
+12 −4
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.content.IntentFilter;
import android.content.om.OverlayInfo;
import android.content.om.OverlayManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.Flags;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -434,10 +435,17 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
                    // No preferred default, so permit uninstall only when
                    // there is more than one candidate
                    enabled = (mHomePackages.size() > 1);
                } else if (mPackageInfo.packageName.equals(currentDefaultHome.getPackageName())) {
                    if (Flags.improveHomeAppBehavior()) {
                        // Allow uninstallation of current home app if it is a non-system app
                        // and/or there are other candidate apps available.
                        if (mPackageInfo.applicationInfo.isSystemApp()
                                || mHomePackages.size() == 1) {
                            enabled = false;
                        }
                    } else {
                    // There is an explicit default home app -- forbid uninstall of
                    // that one, but permit it for installed-but-inactive ones.
                    enabled = !mPackageInfo.packageName.equals(currentDefaultHome.getPackageName());
                        enabled = false;
                    }
                }
            }
        }
+15 −4
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.ComponentName
import android.content.Context
import android.content.om.OverlayManager
import android.content.pm.ApplicationInfo
import android.content.pm.Flags
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.util.Log
@@ -95,7 +96,7 @@ class AppButtonRepository(private val context: Context) {

            isDisallowControl(app) -> return false

            uninstallDisallowedDueToHomeApp(app.packageName) -> return false
            uninstallDisallowedDueToHomeApp(app) -> return false

            // Resource overlays can be uninstalled iff they are public (installed on /data) and
            // disabled. ("Enabled" means they are in use by resource management.)
@@ -113,7 +114,8 @@ class AppButtonRepository(private val context: Context) {
     * can go to Home settings and pick a different one, after which we'll permit uninstallation
     * of the now-not-default one.
     */
    private fun uninstallDisallowedDueToHomeApp(packageName: String): Boolean {
    fun uninstallDisallowedDueToHomeApp(applicationInfo: ApplicationInfo): Boolean {
        val packageName = applicationInfo.packageName
        val homePackageInfo = getHomePackageInfo()
        return when {
            packageName !in homePackageInfo.homePackages -> false
@@ -121,8 +123,17 @@ class AppButtonRepository(private val context: Context) {
            // Disallow uninstall when this is the only home app.
            homePackageInfo.homePackages.size == 1 -> true

            packageName == homePackageInfo.currentDefaultHome?.packageName -> {
                if (Flags.improveHomeAppBehavior()) {
                    // Disallow the uninstallation of the current home app if it is a system app.
                    return applicationInfo.isSystemApp()
                } else {
                    // Disallow if this is the explicit default home app.
            else -> packageName == homePackageInfo.currentDefaultHome?.packageName
                    return true
                }
            }

            else -> false
        }
    }

+40 −7
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -38,15 +39,18 @@ import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.om.OverlayInfo;
import android.content.om.OverlayManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.Flags;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.os.UserManager;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.util.ArraySet;
import android.view.View;

@@ -107,7 +111,7 @@ public class AppButtonsPreferenceControllerTest {
    @Mock
    private OverlayManager mOverlayManager;
    @Mock
    private PackageManager mPackageManger;
    private PackageManager mPackageManager;
    @Mock
    private DevicePolicyManager mDpm;
    @Mock
@@ -132,7 +136,7 @@ public class AppButtonsPreferenceControllerTest {
        mContext = RuntimeEnvironment.application;
        doReturn(mDpm).when(mSettingsActivity).getSystemService(Context.DEVICE_POLICY_SERVICE);
        doReturn(mUserManager).when(mSettingsActivity).getSystemService(Context.USER_SERVICE);
        doReturn(mPackageManger).when(mSettingsActivity).getPackageManager();
        doReturn(mPackageManager).when(mSettingsActivity).getPackageManager();
        doReturn(mAm).when(mSettingsActivity).getSystemService(Context.ACTIVITY_SERVICE);
        doReturn(mOverlayManager).when(mSettingsActivity).
                getSystemService(OverlayManager.class);
@@ -184,7 +188,7 @@ public class AppButtonsPreferenceControllerTest {
    @Test
    public void retrieveAppEntry_hasAppEntry_notNull()
            throws PackageManager.NameNotFoundException {
        doReturn(mPackageInfo).when(mPackageManger).getPackageInfo(anyString(), anyInt());
        doReturn(mPackageInfo).when(mPackageManager).getPackageInfo(anyString(), anyInt());

        mController.retrieveAppEntry();

@@ -195,7 +199,7 @@ public class AppButtonsPreferenceControllerTest {
    @Test
    public void retrieveAppEntry_noAppEntry_null() throws PackageManager.NameNotFoundException {
        doReturn(null).when(mState).getEntry(eq(PACKAGE_NAME), anyInt());
        doReturn(mPackageInfo).when(mPackageManger).getPackageInfo(anyString(), anyInt());
        doReturn(mPackageInfo).when(mPackageManager).getPackageInfo(anyString(), anyInt());

        mController.retrieveAppEntry();

@@ -207,7 +211,7 @@ public class AppButtonsPreferenceControllerTest {
    public void retrieveAppEntry_throwException_null() throws
            PackageManager.NameNotFoundException {
        doReturn(mAppEntry).when(mState).getEntry(anyString(), anyInt());
        doThrow(new PackageManager.NameNotFoundException()).when(mPackageManger).getPackageInfo(
        doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager).getPackageInfo(
                anyString(), anyInt());

        mController.retrieveAppEntry();
@@ -225,7 +229,7 @@ public class AppButtonsPreferenceControllerTest {

    @Test
    public void updateOpenButton_haveLaunchIntent_buttonShouldBeEnable() {
        doReturn(new Intent()).when(mPackageManger).getLaunchIntentForPackage(anyString());
        doReturn(new Intent()).when(mPackageManager).getLaunchIntentForPackage(anyString());

        mController.updateOpenButton();

@@ -346,6 +350,35 @@ public class AppButtonsPreferenceControllerTest {
        verify(mButtonPrefs).setButton2Enabled(false);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_IMPROVE_HOME_APP_BEHAVIOR)
    public void updateUninstallButton_isNotSystemAndIsCurrentHomeAndHasOneHome_setButtonDisable() {
        doReturn(false).when(mController).isSystemPackage(any(), any(), any());
        doReturn(new ComponentName(PACKAGE_NAME, "cls")).when(mPackageManager).getHomeActivities(
                anyList());

        mController.mHomePackages.add(PACKAGE_NAME);

        mController.updateUninstallButton();

        verify(mButtonPrefs).setButton2Enabled(false);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_IMPROVE_HOME_APP_BEHAVIOR)
    public void updateUninstallButton_isNotSystemAndIsCurrentHomeAndHasOtherHome_setButtonEnable() {
        doReturn(false).when(mController).isSystemPackage(any(), any(), any());
        doReturn(new ComponentName(PACKAGE_NAME, "cls")).when(mPackageManager).getHomeActivities(
                anyList());

        mController.mHomePackages.add(PACKAGE_NAME);
        mController.mHomePackages.add("com.android.home.fake");

        mController.updateUninstallButton();

        verify(mButtonPrefs).setButton2Enabled(true);
    }

    @Test
    public void updateUninstallButton_isSystemRro_setButtonDisable() {
        mAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
@@ -477,7 +510,7 @@ public class AppButtonsPreferenceControllerTest {
            throws PackageManager.NameNotFoundException {
        doReturn(AppButtonsPreferenceController.AVAILABLE)
                .when(mController).getAvailabilityStatus();
        doReturn(mPackageInfo).when(mPackageManger).getPackageInfo(anyString(), anyInt());
        doReturn(mPackageInfo).when(mPackageManager).getPackageInfo(anyString(), anyInt());
        doReturn(mButtonPrefs).when(mScreen).findPreference(anyString());
        mController.displayPreference(mScreen);
        mController.mButtonsPref = null;
+61 −0
Original line number Diff line number Diff line
@@ -20,8 +20,11 @@ import android.app.ActivityManager
import android.content.ComponentName
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
import android.content.pm.Flags
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.platform.test.annotations.RequiresFlagsEnabled
import androidx.core.os.bundleOf
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -126,9 +129,62 @@ class AppButtonRepositoryTest {
        assertThat(homePackageInfo.homePackages).containsExactly(PACKAGE_NAME)
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_IMPROVE_HOME_APP_BEHAVIOR)
    fun uninstallDisallowedDueToHomeApp_isNotSystemAndIsCurrentHomeAndHasOnlyOneHomeApp() {
        val app = ApplicationInfo().apply {
            packageName = PACKAGE_NAME
        }

        mockGetHomeActivities(
            homeActivities = listOf(RESOLVE_INFO),
            currentDefaultHome = COMPONENT_NAME,
        )

        val value = appButtonRepository.uninstallDisallowedDueToHomeApp(app)

        assertThat(value).isTrue()
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_IMPROVE_HOME_APP_BEHAVIOR)
    fun uninstallDisallowedDueToHomeApp_isNotSystemAndIsCurrentHomeAndHasOtherHomeApps() {
        val app = ApplicationInfo().apply {
            packageName = PACKAGE_NAME
        }

        mockGetHomeActivities(
            homeActivities = listOf(RESOLVE_INFO, RESOLVE_INFO_FAKE),
            currentDefaultHome = COMPONENT_NAME,
        )

        val value = appButtonRepository.uninstallDisallowedDueToHomeApp(app)

        assertThat(value).isFalse()
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_IMPROVE_HOME_APP_BEHAVIOR)
    fun uninstallDisallowedDueToHomeApp_isSystemAndIsCurrentHomeAndHasOtherHomeApps() {
        val app = ApplicationInfo().apply {
            packageName = PACKAGE_NAME
            flags = ApplicationInfo.FLAG_SYSTEM
        }

        mockGetHomeActivities(
            homeActivities = listOf(RESOLVE_INFO, RESOLVE_INFO_FAKE),
            currentDefaultHome = COMPONENT_NAME,
        )

        val value = appButtonRepository.uninstallDisallowedDueToHomeApp(app)

        assertThat(value).isTrue()
    }

    private companion object {
        const val PACKAGE_NAME = "packageName"
        const val PACKAGE_NAME_ALTERNATE = "packageName.alternate"
        const val PACKAGE_NAME_FAKE = "packageName.fake"
        const val ACTIVITY_NAME = "activityName"
        val COMPONENT_NAME = ComponentName(PACKAGE_NAME, ACTIVITY_NAME)
        val RESOLVE_INFO = ResolveInfo().apply {
@@ -136,6 +192,11 @@ class AppButtonRepositoryTest {
                packageName = PACKAGE_NAME
            }
        }
        val RESOLVE_INFO_FAKE = ResolveInfo().apply {
            activityInfo = ActivityInfo().apply {
                packageName = PACKAGE_NAME_FAKE
            }
        }
        val RESOLVE_INFO_WITH_ALTERNATE = ResolveInfo().apply {
            activityInfo = ActivityInfo().apply {
                packageName = PACKAGE_NAME