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

Commit 61d27141 authored by Denis Kuznetsov's avatar Denis Kuznetsov
Browse files

Refactoring: introduce UserLogoutInteractor

Change code to use Flows for detecting possibility of Logout, and
introduce UserLogoutInteractor that would handle logout-specific
scenarios.

This change in a preparation step for adding desktop-style logout
functionality.

Bug: 375384623
Bug: 206032495
Flag: EXEMPT Mechanical refactoring
Test: atest UserLogoutInteractorTest
Test: atest UserRepositoryImplTest
Test: atest KeyguardIndicationControllerBaseTest
Test: atest GlobalActionsDialogLiteTest
Test: atest KeyguardUpdateMonitorTest
Change-Id: Ib54a6530176bcd937ad9005be6da675ad06d41e6
parent f7f4ce2e
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.user.domain.interactor.UserLogoutInteractor;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wakelock.WakeLockFake;
@@ -160,6 +161,8 @@ public class KeyguardIndicationControllerBaseTest extends SysuiTestCase {
    @Mock
    protected DeviceEntryFingerprintAuthInteractor mDeviceEntryFingerprintAuthInteractor;
    @Mock
    protected UserLogoutInteractor mUserLogoutInteractor;
    @Mock
    protected ScreenLifecycle mScreenLifecycle;
    @Mock
    protected AuthController mAuthController;
@@ -248,6 +251,9 @@ public class KeyguardIndicationControllerBaseTest extends SysuiTestCase {

        when(mFaceHelpMessageDeferralFactory.create()).thenReturn(mFaceHelpMessageDeferral);
        when(mDeviceEntryFingerprintAuthInteractor.isEngaged()).thenReturn(mock(StateFlow.class));
        StateFlow mockLogoutEnabledFlow = mock(StateFlow.class);
        when(mockLogoutEnabledFlow.getValue()).thenReturn(false);
        when(mUserLogoutInteractor.isLogoutEnabled()).thenReturn(mockLogoutEnabledFlow);

        mIndicationHelper = new IndicationHelper(mKeyguardUpdateMonitor);

@@ -291,7 +297,8 @@ public class KeyguardIndicationControllerBaseTest extends SysuiTestCase {
                KeyguardInteractorFactory.create(mFlags).getKeyguardInteractor(),
                mBiometricMessageInteractor,
                mDeviceEntryFingerprintAuthInteractor,
                mDeviceEntryFaceAuthInteractor
                mDeviceEntryFaceAuthInteractor,
                mUserLogoutInteractor
        );
        mController.init();
        mController.setIndicationArea(mIndicationArea);
+6 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@

package com.android.systemui.user.data.repository

import android.app.admin.devicePolicyManager
import android.content.pm.UserInfo
import android.os.UserHandle
import android.os.UserManager
@@ -24,6 +25,7 @@ import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.broadcastDispatcher
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
@@ -57,6 +59,8 @@ class UserRepositoryImplTest : SysuiTestCase() {
    private val testDispatcher = kosmos.testDispatcher
    private val testScope = kosmos.testScope
    private val globalSettings = kosmos.fakeGlobalSettings
    private val broadcastDispatcher = kosmos.broadcastDispatcher
    private val devicePolicyManager = kosmos.devicePolicyManager

    @Mock private lateinit var manager: UserManager

@@ -317,6 +321,8 @@ class UserRepositoryImplTest : SysuiTestCase() {
            backgroundDispatcher = testDispatcher,
            globalSettings = globalSettings,
            tracker = tracker,
            broadcastDispatcher = broadcastDispatcher,
            devicePolicyManager = devicePolicyManager,
        )
    }

+83 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.android.systemui.user.domain.interactor

import android.content.pm.UserInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class UserLogoutInteractorTest : SysuiTestCase() {

    private val kosmos = testKosmos().useUnconfinedTestDispatcher()

    private val userRepository = kosmos.fakeUserRepository
    private val testScope = kosmos.testScope

    private val underTest = kosmos.userLogoutInteractor

    @Before
    fun setUp() {
        userRepository.setUserInfos(USER_INFOS)
        runBlocking { userRepository.setSelectedUserInfo(USER_INFOS[1]) }
    }

    @Test
    fun logOut_doesNothing_whenAdminDisabledSecondaryLogout() {
        testScope.runTest {
            val isLogoutEnabled by collectLastValue(underTest.isLogoutEnabled)
            val lastLogoutCount = userRepository.logOutSecondaryUserCallCount
            userRepository.setSecondaryUserLogoutEnabled(false)
            assertThat(isLogoutEnabled).isFalse()
            underTest.logOut()
            assertThat(userRepository.logOutSecondaryUserCallCount).isEqualTo(lastLogoutCount)
        }
    }

    @Test
    fun logOut_logsOut_whenAdminEnabledSecondaryLogout() {
        testScope.runTest {
            val isLogoutEnabled by collectLastValue(underTest.isLogoutEnabled)
            val lastLogoutCount = userRepository.logOutSecondaryUserCallCount
            userRepository.setSecondaryUserLogoutEnabled(true)
            assertThat(isLogoutEnabled).isTrue()
            underTest.logOut()
            assertThat(userRepository.logOutSecondaryUserCallCount).isEqualTo(lastLogoutCount + 1)
        }
    }

    companion object {
        private val USER_INFOS =
            listOf(UserInfo(0, "System user", 0), UserInfo(10, "Regular user", 0))
    }
}
+0 −31
Original line number Diff line number Diff line
@@ -219,7 +219,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    private static final int MSG_USER_UNLOCKED = 334;
    private static final int MSG_ASSISTANT_STACK_CHANGED = 335;
    private static final int MSG_BIOMETRIC_AUTHENTICATION_CONTINUE = 336;
    private static final int MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED = 337;
    private static final int MSG_TELEPHONY_CAPABLE = 338;
    private static final int MSG_TIMEZONE_UPDATE = 339;
    private static final int MSG_USER_STOPPED = 340;
@@ -402,7 +401,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
    protected int mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
    private boolean mFingerprintDetectRunning;
    private boolean mIsDreaming;
    private boolean mLogoutEnabled;
    private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    private final FingerprintInteractiveToAuthProvider mFingerprintInteractiveToAuthProvider;

@@ -1739,9 +1737,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                        mHandler.obtainMessage(MSG_SERVICE_STATE_CHANGE, subId, 0, serviceState));
            } else if (TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED.equals(action)) {
                mHandler.sendEmptyMessage(MSG_SIM_SUBSCRIPTION_INFO_CHANGED);
            } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
                    action)) {
                mHandler.sendEmptyMessage(MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED);
            }
        }
    };
@@ -2328,9 +2323,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                    case MSG_BIOMETRIC_AUTHENTICATION_CONTINUE:
                        updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
                        break;
                    case MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED:
                        updateLogoutEnabled();
                        break;
                    case MSG_TELEPHONY_CAPABLE:
                        updateTelephonyCapable((boolean) msg.obj);
                        break;
@@ -2496,7 +2488,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        boolean isUserUnlocked = mUserManager.isUserUnlocked(user);
        mLogger.logUserUnlockedInitialState(user, isUserUnlocked);
        mUserIsUnlocked.put(user, isUserUnlocked);
        mLogoutEnabled = mDevicePolicyManager.isLogoutEnabled();
        updateSecondaryLockscreenRequirement(user);
        List<UserInfo> allUsers = mUserManager.getUsers();
        for (UserInfo userInfo : allUsers) {
@@ -4062,28 +4053,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        return null; // not found
    }

    /**
     * @return a cached version of DevicePolicyManager.isLogoutEnabled()
     */
    public boolean isLogoutEnabled() {
        return mLogoutEnabled;
    }

    private void updateLogoutEnabled() {
        Assert.isMainThread();
        boolean logoutEnabled = mDevicePolicyManager.isLogoutEnabled();
        if (mLogoutEnabled != logoutEnabled) {
            mLogoutEnabled = logoutEnabled;

            for (int i = 0; i < mCallbacks.size(); i++) {
                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
                if (cb != null) {
                    cb.onLogoutEnabledChanged();
                }
            }
        }
    }

    protected int getBiometricLockoutDelay() {
        return BIOMETRIC_LOCKOUT_RESET_DELAY_MS;
    }
+0 −5
Original line number Diff line number Diff line
@@ -285,11 +285,6 @@ public class KeyguardUpdateMonitorCallback {
     */
    public void onTrustAgentErrorMessage(CharSequence message) { }

    /**
     * Called when a value of logout enabled is change.
     */
    public void onLogoutEnabledChanged() { }

    /**
     * Called when authenticated fingerprint biometrics are cleared.
     */
Loading