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

Commit 27bed0c6 authored by Lucas Silva's avatar Lucas Silva
Browse files

Refactor the CommunalManager system service to simplify logic.

Test: locally on device
Test: atest FrameworksMockingServicesTests:CommunalManagerServiceTest
Change-Id: Ia91381e6836eceeaeb61c9ee2a5c32655411b55e
parent 9c953855
Loading
Loading
Loading
Loading
+13 −48
Original line number Original line Diff line number Diff line
@@ -37,15 +37,10 @@ import android.content.Intent;
import android.content.IntentSender;
import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ApplicationInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.Log;
import android.util.Log;
import android.util.Slog;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.LaunchAfterAuthenticationActivity;
import com.android.internal.app.LaunchAfterAuthenticationActivity;
@@ -55,6 +50,7 @@ import com.android.server.wm.ActivityInterceptorCallback;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;


import java.util.Arrays;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.HashSet;
import java.util.Set;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -70,9 +66,6 @@ public final class CommunalManagerService extends SystemService {
    private final ActivityTaskManagerInternal mAtmInternal;
    private final ActivityTaskManagerInternal mAtmInternal;
    private final KeyguardManager mKeyguardManager;
    private final KeyguardManager mKeyguardManager;
    private final AtomicBoolean mCommunalViewIsShowing = new AtomicBoolean(false);
    private final AtomicBoolean mCommunalViewIsShowing = new AtomicBoolean(false);
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private final Set<String> mEnabledApps = new HashSet<>();
    private final SettingsObserver mSettingsObserver;
    private final BinderService mBinderService;
    private final BinderService mBinderService;


    /**
    /**
@@ -130,7 +123,6 @@ public final class CommunalManagerService extends SystemService {
    public CommunalManagerService(Context context) {
    public CommunalManagerService(Context context) {
        super(context);
        super(context);
        mContext = context;
        mContext = context;
        mSettingsObserver = new SettingsObserver();
        mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
        mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
        mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
        mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
        mBinderService = new BinderService();
        mBinderService = new BinderService();
@@ -141,35 +133,28 @@ public final class CommunalManagerService extends SystemService {
        return mBinderService;
        return mBinderService;
    }
    }


    @VisibleForTesting
    @Override
    void publishBinderServices() {
    public void onStart() {
        publishBinderService(Context.COMMUNAL_MANAGER_SERVICE, mBinderService);
        publishBinderService(Context.COMMUNAL_MANAGER_SERVICE, mBinderService);
    }
    }


    @Override
    @Override
    public void onStart() {
    public void onBootPhase(int phase) {
        publishBinderServices();
        if (phase != SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) return;
        mAtmInternal.registerActivityStartInterceptor(COMMUNAL_MODE_ORDERED_ID,
        mAtmInternal.registerActivityStartInterceptor(
                COMMUNAL_MODE_ORDERED_ID,
                mActivityInterceptorCallback);
                mActivityInterceptorCallback);

        updateSelectedApps();
        mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
                Settings.Secure.COMMUNAL_MODE_PACKAGES), false, mSettingsObserver,
                UserHandle.USER_SYSTEM);
    }
    }


    @VisibleForTesting
    private Set<String> getUserEnabledApps() {
    void updateSelectedApps() {
        final String encodedApps = Settings.Secure.getStringForUser(
        final String encodedApps = Settings.Secure.getStringForUser(
                mContext.getContentResolver(),
                mContext.getContentResolver(),
                Settings.Secure.COMMUNAL_MODE_PACKAGES,
                Settings.Secure.COMMUNAL_MODE_PACKAGES,
                UserHandle.USER_SYSTEM);
                UserHandle.USER_SYSTEM);


        mEnabledApps.clear();
        return TextUtils.isEmpty(encodedApps)

                ? Collections.emptySet()
        if (!TextUtils.isEmpty(encodedApps)) {
                : new HashSet<>(Arrays.asList(encodedApps.split(DELIMITER)));
            mEnabledApps.addAll(Arrays.asList(encodedApps.split(DELIMITER)));
        }
    }
    }


    private boolean isAppAllowed(ApplicationInfo appInfo) {
    private boolean isAppAllowed(ApplicationInfo appInfo) {
@@ -177,20 +162,11 @@ public final class CommunalManagerService extends SystemService {
            return true;
            return true;
        }
        }


        if (appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) {
            if (DEBUG) Slog.d(TAG, "Allowlisted as system app: " + appInfo.packageName);
            return isAppEnabledByUser(appInfo);
        }

        return isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, appInfo)
        return isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, appInfo)
                && isAppEnabledByUser(appInfo);
                && getUserEnabledApps().contains(appInfo.packageName);
    }

    private boolean isAppEnabledByUser(ApplicationInfo appInfo) {
        return mEnabledApps.contains(appInfo.packageName);
    }
    }


    private boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
    private static boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
        return CompatChanges.isChangeEnabled(changeId, appInfo.packageName, UserHandle.SYSTEM);
        return CompatChanges.isChangeEnabled(changeId, appInfo.packageName, UserHandle.SYSTEM);
    }
    }


@@ -199,17 +175,6 @@ public final class CommunalManagerService extends SystemService {
        return !isAppAllowed(activityInfo.applicationInfo);
        return !isAppAllowed(activityInfo.applicationInfo);
    }
    }


    private final class SettingsObserver extends ContentObserver {
        SettingsObserver() {
            super(mHandler);
        }

        @Override
        public void onChange(boolean selfChange, Uri uri) {
            mContext.getMainExecutor().execute(CommunalManagerService.this::updateSelectedApps);
        }
    }

    private final class BinderService extends ICommunalManager.Stub {
    private final class BinderService extends ICommunalManager.Stub {
        /**
        /**
         * Sets whether or not we are in communal mode.
         * Sets whether or not we are in communal mode.
+20 −22
Original line number Original line Diff line number Diff line
@@ -20,7 +20,6 @@ import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;


import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.communal.CommunalManagerService.ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT;
import static com.android.server.communal.CommunalManagerService.ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT;
@@ -51,6 +50,7 @@ import androidx.test.filters.SmallTest;


import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.wm.ActivityInterceptorCallback;
import com.android.server.wm.ActivityInterceptorCallback;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;


@@ -98,7 +98,6 @@ public class CommunalManagerServiceTest {
        mMockingSession = mockitoSession()
        mMockingSession = mockitoSession()
                .initMocks(this)
                .initMocks(this)
                .mockStatic(CompatChanges.class)
                .mockStatic(CompatChanges.class)
                .mockStatic(KeyguardManager.class)
                .strictness(Strictness.WARN)
                .strictness(Strictness.WARN)
                .startMocking();
                .startMocking();


@@ -114,9 +113,7 @@ public class CommunalManagerServiceTest {
                eq(Manifest.permission.WRITE_COMMUNAL_STATE), anyString());
                eq(Manifest.permission.WRITE_COMMUNAL_STATE), anyString());


        mService = new CommunalManagerService(mContextSpy);
        mService = new CommunalManagerService(mContextSpy);
        spyOn(mService);
        mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
        doNothing().when(mService).publishBinderServices();
        mService.onStart();


        ArgumentCaptor<ActivityInterceptorCallback> activityInterceptorCaptor =
        ArgumentCaptor<ActivityInterceptorCallback> activityInterceptorCaptor =
                ArgumentCaptor.forClass(ActivityInterceptorCallback.class);
                ArgumentCaptor.forClass(ActivityInterceptorCallback.class);
@@ -166,51 +163,55 @@ public class CommunalManagerServiceTest {
    private void allowPackages(String packages) {
    private void allowPackages(String packages) {
        Settings.Secure.putStringForUser(mContextSpy.getContentResolver(),
        Settings.Secure.putStringForUser(mContextSpy.getContentResolver(),
                Settings.Secure.COMMUNAL_MODE_PACKAGES, packages, UserHandle.USER_SYSTEM);
                Settings.Secure.COMMUNAL_MODE_PACKAGES, packages, UserHandle.USER_SYSTEM);
        mService.updateSelectedApps();
    }

    private void assertDoesIntercept() {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNotNull();
    }

    private void assertDoesNotIntercept() {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNull();
    }
    }


    @Test
    @Test
    public void testIntercept_unlocked_communalOff_appNotEnabled_showWhenLockedOff() {
    public void testIntercept_unlocked_communalOff_appNotEnabled_showWhenLockedOff() {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
        mAInfo.flags = 0;
        mAInfo.flags = 0;
        assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNull();
        assertDoesNotIntercept();
    }
    }


    @Test
    @Test
    public void testIntercept_unlocked_communalOn_appNotEnabled_showWhenLockedOff()
    public void testIntercept_unlocked_communalOn_appNotEnabled_showWhenLockedOff()
            throws RemoteException {
            throws RemoteException {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        mBinder.setCommunalViewShowing(true);
        mBinder.setCommunalViewShowing(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
        mAInfo.flags = 0;
        mAInfo.flags = 0;
        assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNull();
        assertDoesNotIntercept();
    }
    }


    @Test
    @Test
    public void testIntercept_locked_communalOff_appNotEnabled_showWhenLockedOff() {
    public void testIntercept_locked_communalOff_appNotEnabled_showWhenLockedOff() {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        mAInfo.flags = 0;
        mAInfo.flags = 0;
        assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNull();
        assertDoesNotIntercept();
    }
    }


    @Test
    @Test
    public void testIntercept_locked_communalOn_appNotEnabled_showWhenLockedOff_allowlistEnabled()
    public void testIntercept_locked_communalOn_appNotEnabled_showWhenLockedOff_allowlistEnabled()
            throws RemoteException {
            throws RemoteException {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        mBinder.setCommunalViewShowing(true);
        mBinder.setCommunalViewShowing(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
                UserHandle.SYSTEM)).thenReturn(true);
                UserHandle.SYSTEM)).thenReturn(true);
        mAInfo.flags = 0;
        mAInfo.flags = 0;
        assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNotNull();
        assertDoesIntercept();
    }
    }


    @Test
    @Test
    public void testIntercept_locked_communalOn_appNotEnabled_showWhenLockedOn_allowlistEnabled()
    public void testIntercept_locked_communalOn_appNotEnabled_showWhenLockedOn_allowlistEnabled()
            throws RemoteException {
            throws RemoteException {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        mBinder.setCommunalViewShowing(true);
        mBinder.setCommunalViewShowing(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
@@ -218,13 +219,12 @@ public class CommunalManagerServiceTest {
        mAInfo.flags = FLAG_SHOW_WHEN_LOCKED;
        mAInfo.flags = FLAG_SHOW_WHEN_LOCKED;


        allowPackages("package1,package2");
        allowPackages("package1,package2");
        assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNotNull();
        assertDoesIntercept();
    }
    }


    @Test
    @Test
    public void testIntercept_locked_communalOn_appEnabled_showWhenLockedOff_allowlistEnabled()
    public void testIntercept_locked_communalOn_appEnabled_showWhenLockedOff_allowlistEnabled()
            throws RemoteException {
            throws RemoteException {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        mBinder.setCommunalViewShowing(true);
        mBinder.setCommunalViewShowing(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
@@ -233,13 +233,12 @@ public class CommunalManagerServiceTest {


        allowPackages(TEST_PACKAGE_NAME);
        allowPackages(TEST_PACKAGE_NAME);
        // TODO(b/191994709): Fix this assertion once we start checking showWhenLocked
        // TODO(b/191994709): Fix this assertion once we start checking showWhenLocked
        assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNull();
        assertDoesNotIntercept();
    }
    }


    @Test
    @Test
    public void testIntercept_locked_communalOn_appEnabled_showWhenLockedOn_allowlistEnabled()
    public void testIntercept_locked_communalOn_appEnabled_showWhenLockedOn_allowlistEnabled()
            throws RemoteException {
            throws RemoteException {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        mBinder.setCommunalViewShowing(true);
        mBinder.setCommunalViewShowing(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
@@ -248,13 +247,12 @@ public class CommunalManagerServiceTest {
        mAInfo.flags = FLAG_SHOW_WHEN_LOCKED;
        mAInfo.flags = FLAG_SHOW_WHEN_LOCKED;


        allowPackages(TEST_PACKAGE_NAME);
        allowPackages(TEST_PACKAGE_NAME);
        assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNull();
        assertDoesNotIntercept();
    }
    }


    @Test
    @Test
    public void testIntercept_locked_communalOn_appEnabled_showWhenLockedOn_allowlistDisabled()
    public void testIntercept_locked_communalOn_appEnabled_showWhenLockedOn_allowlistDisabled()
            throws RemoteException {
            throws RemoteException {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        mBinder.setCommunalViewShowing(true);
        mBinder.setCommunalViewShowing(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
        when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
@@ -263,6 +261,6 @@ public class CommunalManagerServiceTest {
        mAInfo.flags = FLAG_SHOW_WHEN_LOCKED;
        mAInfo.flags = FLAG_SHOW_WHEN_LOCKED;


        allowPackages(TEST_PACKAGE_NAME);
        allowPackages(TEST_PACKAGE_NAME);
        assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNotNull();
        assertDoesIntercept();
    }
    }
}
}