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 Diff line number Diff line
@@ -37,15 +37,10 @@ import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ActivityInfo;
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.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;

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

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -70,9 +66,6 @@ public final class CommunalManagerService extends SystemService {
    private final ActivityTaskManagerInternal mAtmInternal;
    private final KeyguardManager mKeyguardManager;
    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;

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

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

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

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

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

        mEnabledApps.clear();

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

    private boolean isAppAllowed(ApplicationInfo appInfo) {
@@ -177,20 +162,11 @@ public final class CommunalManagerService extends SystemService {
            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)
                && isAppEnabledByUser(appInfo);
    }

    private boolean isAppEnabledByUser(ApplicationInfo appInfo) {
        return mEnabledApps.contains(appInfo.packageName);
                && getUserEnabledApps().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);
    }

@@ -199,17 +175,6 @@ public final class CommunalManagerService extends SystemService {
        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 {
        /**
         * Sets whether or not we are in communal mode.
+20 −22
Original line number 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.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.when;
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.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.wm.ActivityInterceptorCallback;
import com.android.server.wm.ActivityTaskManagerInternal;

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

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

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

        ArgumentCaptor<ActivityInterceptorCallback> activityInterceptorCaptor =
                ArgumentCaptor.forClass(ActivityInterceptorCallback.class);
@@ -166,51 +163,55 @@ public class CommunalManagerServiceTest {
    private void allowPackages(String packages) {
        Settings.Secure.putStringForUser(mContextSpy.getContentResolver(),
                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
    public void testIntercept_unlocked_communalOff_appNotEnabled_showWhenLockedOff() {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
        mAInfo.flags = 0;
        assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNull();
        assertDoesNotIntercept();
    }

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

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

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

    @Test
    public void testIntercept_locked_communalOn_appNotEnabled_showWhenLockedOn_allowlistEnabled()
            throws RemoteException {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        mBinder.setCommunalViewShowing(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        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;

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

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

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

    @Test
    public void testIntercept_locked_communalOn_appEnabled_showWhenLockedOn_allowlistEnabled()
            throws RemoteException {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        mBinder.setCommunalViewShowing(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        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;

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

    @Test
    public void testIntercept_locked_communalOn_appEnabled_showWhenLockedOn_allowlistDisabled()
            throws RemoteException {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        mBinder.setCommunalViewShowing(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
        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;

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