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

Commit 8615a902 authored by Doris Ling's avatar Doris Ling
Browse files

Hide mainline module apps in settings.

- check whether an app is system hidden module and do not include them
when we retrieve the installed apps list.

Bug: 120546598
Test: make RunSettingsLibRoboTests
Change-Id: I7dc78a62bf8664d4316511467a9e046a1726935f
parent a32c79d3
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.settingslib.applications;

import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.IntentFilter;
@@ -123,4 +124,12 @@ public class AppUtils {
        return null;
    }

    /**
     * Returns a boolean indicating whether the given package is a hidden system module
     */
    public static boolean isHiddenSystemModule(Context context, String packageName) {
        return ApplicationsState.getInstance((Application) context.getApplicationContext())
            .isHiddenModule(packageName);
    }

}
+27 −3
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageStats;
@@ -71,6 +72,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
@@ -95,9 +97,14 @@ public class ApplicationsState {
    static ApplicationsState sInstance;

    public static ApplicationsState getInstance(Application app) {
        return getInstance(app, AppGlobals.getPackageManager());
    }

    @VisibleForTesting
    static ApplicationsState getInstance(Application app, IPackageManager iPackageManager) {
        synchronized (sLock) {
            if (sInstance == null) {
                sInstance = new ApplicationsState(app);
                sInstance = new ApplicationsState(app, iPackageManager);
            }
            return sInstance;
        }
@@ -132,6 +139,7 @@ public class ApplicationsState {
    String mCurComputingSizePkg;
    int mCurComputingSizeUserId;
    boolean mSessionsChanged;
    final HashSet<String> mHiddenModules = new HashSet<>();

    // Temporary for dispatching session callbacks.  Only touched by main thread.
    final ArrayList<WeakReference<Session>> mActiveSessions = new ArrayList<>();
@@ -172,11 +180,11 @@ public class ApplicationsState {
            FLAG_SESSION_REQUEST_HOME_APP | FLAG_SESSION_REQUEST_ICONS |
            FLAG_SESSION_REQUEST_SIZES | FLAG_SESSION_REQUEST_LAUNCHER;

    private ApplicationsState(Application app) {
    private ApplicationsState(Application app, IPackageManager iPackageManager) {
        mContext = app;
        mPm = mContext.getPackageManager();
        mDrawableFactory = IconDrawableFactory.newInstance(mContext);
        mIpm = AppGlobals.getPackageManager();
        mIpm = iPackageManager;
        mUm = mContext.getSystemService(UserManager.class);
        mStats = mContext.getSystemService(StorageStatsManager.class);
        for (int userId : mUm.getProfileIdsWithDisabled(UserHandle.myUserId())) {
@@ -194,6 +202,13 @@ public class ApplicationsState {
        mRetrieveFlags = PackageManager.MATCH_DISABLED_COMPONENTS |
                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;

        final List<ModuleInfo> moduleInfos = mPm.getInstalledModules(0 /* flags */);
        for (ModuleInfo info : moduleInfos) {
            if (info.isHidden()) {
                mHiddenModules.add(info.getPackageName());
            }
        }

        /**
         * This is a trick to prevent the foreground thread from being delayed.
         * The problem is that Dalvik monitors are initially spin locks, to keep
@@ -283,6 +298,10 @@ public class ApplicationsState {
                }
                mHaveDisabledApps = true;
            }
            if (isHiddenModule(info.packageName)) {
                mApplications.remove(i--);
                continue;
            }
            if (!mHaveInstantApps && AppUtils.isInstant(info)) {
                mHaveInstantApps = true;
            }
@@ -314,10 +333,15 @@ public class ApplicationsState {
    public boolean haveDisabledApps() {
        return mHaveDisabledApps;
    }

    public boolean haveInstantApps() {
        return mHaveInstantApps;
    }

    boolean isHiddenModule(String packageName) {
        return mHiddenModules.contains(packageName);
    }

    void doPauseIfNeededLocked() {
        if (!mResumed) {
            return;
+80 −29
Original line number Diff line number Diff line
@@ -18,7 +18,9 @@ package com.android.settingslib.applications;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.shadow.api.Shadow.extract;
@@ -33,12 +35,16 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.IconDrawableFactory;

import com.android.settingslib.applications.ApplicationsState.AppEntry;
@@ -46,11 +52,11 @@ import com.android.settingslib.applications.ApplicationsState.Callbacks;
import com.android.settingslib.applications.ApplicationsState.Session;
import com.android.settingslib.testutils.shadow.ShadowUserManager;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -78,6 +84,8 @@ public class ApplicationsStateRoboTest {

    /** Class under test */
    private ApplicationsState mApplicationsState;
    private Session mSession;


    @Mock
    private Callbacks mCallbacks;
@@ -85,6 +93,8 @@ public class ApplicationsStateRoboTest {
    private ArgumentCaptor<ArrayList<AppEntry>> mAppEntriesCaptor;
    @Mock
    private StorageStatsManager mStorageStatsManager;
    @Mock
    private IPackageManager mPackageManagerService;

    @Implements(value = IconDrawableFactory.class)
    public static class ShadowIconDrawableFactory {
@@ -99,6 +109,11 @@ public class ApplicationsStateRoboTest {
    public static class ShadowPackageManager extends
            org.robolectric.shadows.ShadowApplicationPackageManager {

        // test installed modules, 2 regular, 2 hidden
        private final String[] mModuleNames = {
            "test.module.1", "test.hidden.module.2", "test.hidden.module.3", "test.module.4"};
        private final List<ModuleInfo> mInstalledModules = new ArrayList<>();

        @Implementation
        protected ComponentName getHomeActivities(List<ResolveInfo> outActivities) {
            ResolveInfo resolveInfo = new ResolveInfo();
@@ -109,6 +124,16 @@ public class ApplicationsStateRoboTest {
            return ComponentName.createRelative(resolveInfo.activityInfo.packageName, "foo");
        }

        @Implementation
        public List<ModuleInfo> getInstalledModules(int flags) {
            if (mInstalledModules.isEmpty()) {
                for (String moduleName : mModuleNames) {
                    mInstalledModules.add(createModuleInfo(moduleName));
                }
            }
            return mInstalledModules;
        }

        public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
                @PackageManager.ResolveInfoFlags int flags, @UserIdInt int userId) {
            List<ResolveInfo> resolveInfos = new ArrayList<>();
@@ -121,6 +146,15 @@ public class ApplicationsStateRoboTest {
            resolveInfos.add(resolveInfo);
            return resolveInfos;
        }

        private ModuleInfo createModuleInfo(String packageName) {
            final ModuleInfo info = new ModuleInfo();
            info.setName(packageName);
            info.setPackageName(packageName);
            // will treat any app with package name that contains "hidden" as hidden module
            info.setHidden(!TextUtils.isEmpty(packageName) && packageName.contains("hidden"));
            return info;
        }
    }

    @Before
@@ -136,12 +170,28 @@ public class ApplicationsStateRoboTest {
        storageStats.codeBytes = 10;
        storageStats.dataBytes = 20;
        storageStats.cacheBytes = 30;
        when(mStorageStatsManager.queryStatsForPackage(ArgumentMatchers.any(UUID.class),
                anyString(), ArgumentMatchers.any(UserHandle.class))).thenReturn(storageStats);
        when(mStorageStatsManager.queryStatsForPackage(any(UUID.class),
                anyString(), any(UserHandle.class))).thenReturn(storageStats);

        // Set up 3 installed apps, in which 1 is hidden module
        final List<ApplicationInfo> infos = new ArrayList<>();
        infos.add(createApplicationInfo("test.package.1"));
        infos.add(createApplicationInfo("test.hidden.module.2"));
        infos.add(createApplicationInfo("test.package.3"));
        when(mPackageManagerService.getInstalledApplications(
            anyInt() /* flags */, anyInt() /* userId */)).thenReturn(new ParceledListSlice(infos));

        ApplicationsState.sInstance = null;
        mApplicationsState = ApplicationsState.getInstance(RuntimeEnvironment.application);
        mApplicationsState =
            ApplicationsState.getInstance(RuntimeEnvironment.application, mPackageManagerService);
        mApplicationsState.clearEntries();

        mSession = mApplicationsState.newSession(mCallbacks);
    }

    @After
    public void tearDown() {
        mSession.onDestroy();
    }

    private ApplicationInfo createApplicationInfo(String packageName) {
@@ -187,12 +237,11 @@ public class ApplicationsStateRoboTest {

    @Test
    public void testDefaultSessionLoadsAll() {
        Session session = mApplicationsState.newSession(mCallbacks);
        session.onResume();
        mSession.onResume();

        addApp(HOME_PACKAGE_NAME, 1);
        addApp(LAUNCHABLE_PACKAGE_NAME, 2);
        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
        processAllMessages();
        verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());

@@ -211,17 +260,15 @@ public class ApplicationsStateRoboTest {
        AppEntry launchableEntry = findAppEntry(appEntries, 2);
        assertThat(launchableEntry.hasLauncherEntry).isTrue();
        assertThat(launchableEntry.launcherEntryEnabled).isTrue();
        session.onDestroy();
    }

    @Test
    public void testCustomSessionLoadsIconsOnly() {
        Session session = mApplicationsState.newSession(mCallbacks);
        session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_ICONS);
        session.onResume();
        mSession.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_ICONS);
        mSession.onResume();

        addApp(LAUNCHABLE_PACKAGE_NAME, 1);
        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
        processAllMessages();
        verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());

@@ -232,17 +279,15 @@ public class ApplicationsStateRoboTest {
        assertThat(launchableEntry.icon).isNotNull();
        assertThat(launchableEntry.size).isEqualTo(-1);
        assertThat(launchableEntry.hasLauncherEntry).isFalse();
        session.onDestroy();
    }

    @Test
    public void testCustomSessionLoadsSizesOnly() {
        Session session = mApplicationsState.newSession(mCallbacks);
        session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_SIZES);
        session.onResume();
        mSession.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_SIZES);
        mSession.onResume();

        addApp(LAUNCHABLE_PACKAGE_NAME, 1);
        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
        processAllMessages();
        verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());

@@ -253,17 +298,15 @@ public class ApplicationsStateRoboTest {
        assertThat(launchableEntry.icon).isNull();
        assertThat(launchableEntry.hasLauncherEntry).isFalse();
        assertThat(launchableEntry.size).isGreaterThan(0L);
        session.onDestroy();
    }

    @Test
    public void testCustomSessionLoadsHomeOnly() {
        Session session = mApplicationsState.newSession(mCallbacks);
        session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_HOME_APP);
        session.onResume();
        mSession.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_HOME_APP);
        mSession.onResume();

        addApp(HOME_PACKAGE_NAME, 1);
        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
        processAllMessages();
        verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());

@@ -275,17 +318,15 @@ public class ApplicationsStateRoboTest {
        assertThat(launchableEntry.hasLauncherEntry).isFalse();
        assertThat(launchableEntry.size).isEqualTo(-1);
        assertThat(launchableEntry.isHomeApp).isTrue();
        session.onDestroy();
    }

    @Test
    public void testCustomSessionLoadsLeanbackOnly() {
        Session session = mApplicationsState.newSession(mCallbacks);
        session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_LEANBACK_LAUNCHER);
        session.onResume();
        mSession.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_LEANBACK_LAUNCHER);
        mSession.onResume();

        addApp(LAUNCHABLE_PACKAGE_NAME, 1);
        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
        processAllMessages();
        verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());

@@ -298,6 +339,16 @@ public class ApplicationsStateRoboTest {
        assertThat(launchableEntry.isHomeApp).isFalse();
        assertThat(launchableEntry.hasLauncherEntry).isTrue();
        assertThat(launchableEntry.launcherEntryEnabled).isTrue();
        session.onDestroy();
    }

    @Test
    public void onResume_shouldNotIncludeSystemHiddenModule() {
        mSession.onResume();

        final List<ApplicationInfo> mApplications = mApplicationsState.mApplications;
        assertThat(mApplications).hasSize(2);
        assertThat(mApplications.get(0).packageName).isEqualTo("test.package.1");
        assertThat(mApplications.get(1).packageName).isEqualTo("test.package.3");
    }

}