From 5e1ff36d33a6ebf6171d3c7d44f2bee9246fdc2d Mon Sep 17 00:00:00 2001 From: Anton Potapov Date: Wed, 16 Nov 2022 16:47:04 +0000 Subject: [PATCH] Add force updating ManagedProfileController state on user change Fixes: 254024780 Test: Manual + autotests Change-Id: Ic276f886a4862ef20e773f1775d1f80c7f00b1cb --- .../com/android/systemui/qs/QSTileHost.java | 2 +- .../systemui/qs/tiles/WorkModeTile.java | 3 + .../phone/ManagedProfileController.java | 16 +++- .../phone/ManagedProfileControllerImpl.java | 65 +++++++------- .../phone/ManagedProfileControllerImplTest.kt | 88 +++++++++++++++++++ 5 files changed, 141 insertions(+), 33 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 6240c10a9d5b0..cad296b671b30 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -608,7 +608,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener, P if (TextUtils.isEmpty(tileList)) { tileList = res.getString(R.string.quick_settings_tiles); - if (DEBUG) Log.d(TAG, "Loaded tile specs from config: " + tileList); + if (DEBUG) Log.d(TAG, "Loaded tile specs from default config: " + tileList); } else { if (DEBUG) Log.d(TAG, "Loaded tile specs from setting: " + tileList); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java index 7130294deccbe..a6c7781d891c0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java @@ -27,6 +27,7 @@ import android.service.quicksettings.Tile; import android.view.View; import android.widget.Switch; +import androidx.annotation.MainThread; import androidx.annotation.Nullable; import com.android.internal.logging.MetricsLogger; @@ -91,11 +92,13 @@ public class WorkModeTile extends QSTileImpl implements } @Override + @MainThread public void onManagedProfileChanged() { refreshState(mProfileController.isWorkModeEnabled()); } @Override + @MainThread public void onManagedProfileRemoved() { mHost.removeTile(getTileSpec()); mHost.unmarkTileAsAutoAdded(getTileSpec()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java index 4969a1c9a20b9..6811bf6cce393 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java @@ -14,6 +14,8 @@ package com.android.systemui.statusbar.phone; +import androidx.annotation.MainThread; + import com.android.systemui.statusbar.phone.ManagedProfileController.Callback; import com.android.systemui.statusbar.policy.CallbackController; @@ -25,8 +27,20 @@ public interface ManagedProfileController extends CallbackController { boolean isWorkModeEnabled(); - public interface Callback { + /** + * Callback to get updates about work profile status. + */ + interface Callback { + /** + * Called when managed profile change is detected. This always runs on the main thread. + */ + @MainThread void onManagedProfileChanged(); + + /** + * Called when managed profile removal is detected. This always runs on the main thread. + */ + @MainThread void onManagedProfileRemoved(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java index 4beb87ddae2d4..abdf8277e0c9b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java @@ -33,31 +33,28 @@ import java.util.concurrent.Executor; import javax.inject.Inject; -/** - */ @SysUISingleton public class ManagedProfileControllerImpl implements ManagedProfileController { private final List mCallbacks = new ArrayList<>(); - + private final UserTrackerCallback mUserTrackerCallback = new UserTrackerCallback(); private final Context mContext; private final Executor mMainExecutor; private final UserManager mUserManager; private final UserTracker mUserTracker; private final LinkedList mProfiles; + private boolean mListening; private int mCurrentUser; - /** - */ @Inject public ManagedProfileControllerImpl(Context context, @Main Executor mainExecutor, - UserTracker userTracker) { + UserTracker userTracker, UserManager userManager) { mContext = context; mMainExecutor = mainExecutor; - mUserManager = UserManager.get(mContext); + mUserManager = userManager; mUserTracker = userTracker; - mProfiles = new LinkedList(); + mProfiles = new LinkedList<>(); } @Override @@ -100,16 +97,22 @@ public class ManagedProfileControllerImpl implements ManagedProfileController { } } if (mProfiles.size() == 0 && hadProfile && (user == mCurrentUser)) { - for (Callback callback : mCallbacks) { - callback.onManagedProfileRemoved(); - } + mMainExecutor.execute(this::notifyManagedProfileRemoved); } mCurrentUser = user; } } + private void notifyManagedProfileRemoved() { + for (Callback callback : mCallbacks) { + callback.onManagedProfileRemoved(); + } + } + public boolean hasActiveProfile() { - if (!mListening) reloadManagedProfiles(); + if (!mListening || mUserTracker.getUserId() != mCurrentUser) { + reloadManagedProfiles(); + } synchronized (mProfiles) { return mProfiles.size() > 0; } @@ -134,28 +137,28 @@ public class ManagedProfileControllerImpl implements ManagedProfileController { mListening = listening; if (listening) { reloadManagedProfiles(); - mUserTracker.addCallback(mUserChangedCallback, mMainExecutor); + mUserTracker.addCallback(mUserTrackerCallback, mMainExecutor); } else { - mUserTracker.removeCallback(mUserChangedCallback); + mUserTracker.removeCallback(mUserTrackerCallback); } } - private final UserTracker.Callback mUserChangedCallback = - new UserTracker.Callback() { - @Override - public void onUserChanged(int newUser, @NonNull Context userContext) { - reloadManagedProfiles(); - for (Callback callback : mCallbacks) { - callback.onManagedProfileChanged(); - } - } + private final class UserTrackerCallback implements UserTracker.Callback { - @Override - public void onProfilesChanged(@NonNull List profiles) { - reloadManagedProfiles(); - for (Callback callback : mCallbacks) { - callback.onManagedProfileChanged(); - } - } - }; + @Override + public void onUserChanged(int newUser, @NonNull Context userContext) { + reloadManagedProfiles(); + for (Callback callback : mCallbacks) { + callback.onManagedProfileChanged(); + } + } + + @Override + public void onProfilesChanged(@NonNull List profiles) { + reloadManagedProfiles(); + for (Callback callback : mCallbacks) { + callback.onManagedProfileChanged(); + } + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt new file mode 100644 index 0000000000000..7eba3b4633360 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImplTest.kt @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2022 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.statusbar.phone + +import android.content.pm.UserInfo +import android.os.UserManager +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.settings.UserTracker +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.time.FakeSystemClock +import junit.framework.Assert +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.MockitoAnnotations + +@SmallTest +class ManagedProfileControllerImplTest : SysuiTestCase() { + + private val mainExecutor: FakeExecutor = FakeExecutor(FakeSystemClock()) + + private lateinit var controller: ManagedProfileControllerImpl + + @Mock private lateinit var userTracker: UserTracker + @Mock private lateinit var userManager: UserManager + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + + controller = ManagedProfileControllerImpl(context, mainExecutor, userTracker, userManager) + } + + @Test + fun hasWorkingProfile_isWorkModeEnabled_returnsTrue() { + `when`(userTracker.userId).thenReturn(1) + setupWorkingProfile(1) + + Assert.assertEquals(true, controller.hasActiveProfile()) + } + + @Test + fun noWorkingProfile_isWorkModeEnabled_returnsFalse() { + `when`(userTracker.userId).thenReturn(1) + + Assert.assertEquals(false, controller.hasActiveProfile()) + } + + @Test + fun listeningUserChanges_isWorkModeEnabled_returnsTrue() { + `when`(userTracker.userId).thenReturn(1) + controller.addCallback(TestCallback) + `when`(userTracker.userId).thenReturn(2) + setupWorkingProfile(2) + + Assert.assertEquals(true, controller.hasActiveProfile()) + } + + private fun setupWorkingProfile(userId: Int) { + `when`(userManager.getEnabledProfiles(userId)) + .thenReturn( + listOf(UserInfo(userId, "test_user", "", 0, UserManager.USER_TYPE_PROFILE_MANAGED)) + ) + } + + private object TestCallback : ManagedProfileController.Callback { + + override fun onManagedProfileChanged() = Unit + + override fun onManagedProfileRemoved() = Unit + } +}