Update Work profile settings

Change work apps toggle to a primary toggle
make Xprofile contact search toggle disable/enable when work profile is turned off
Add footer and change strings
Add tests

Test: atest ContactSearchPreferenceControllerTest, atest WorkModePreferenceControllerTest

Bug: 253009702 275538029
Change-Id: I3b2044a5fe3f2aff0748d66e701a3f0d7667ab7a
This commit is contained in:
Oli Thompson
2023-03-24 13:01:37 +00:00
parent d865ccc2ed
commit 08b4973f8e
8 changed files with 482 additions and 200 deletions

View File

@@ -5873,12 +5873,8 @@
<string name="add_account_label">Add account</string>
<!-- Label for the state of the work profile [CHAR LIMIT=80] -->
<string name="managed_profile_not_available_label">Work profile isn\u2019t available yet</string>
<!-- This string is the title of a setting. If a user taps the setting, they can turn their work profile on or off. The work profile is a section of their phone that's managed by their employer. "Work" is an adjective. -->
<string name="work_mode_label">Work profile</string>
<!-- This string is located under a setting and describes what the setting does. It's letting a user know whether their work profile is on or off, and they can use the setting to turn it on or off. The work profile is a section of their phone that's managed by their employer. "Work" is an adjective.-->
<string name="work_mode_on_summary">Managed by your organization</string>
<!-- This string is located under a setting and describes what the setting does. It's letting a user know whether their work profile is on or off, and they can use the setting to turn it on or off. The work profile is a section of their phone that's managed by their employer. "Work" is an adjective.-->
<string name="work_mode_off_summary">Apps and notifications are off</string>
<!-- This string is the title of a setting. If a user taps the setting, they can turn their work apps on or off. The work apps are a group of apps that are managed by the the user's employer. While this setting is off, the user cannot interact with those apps or get notifications from them. "Work" is an adjective. -->
<string name="work_mode_label">Work apps</string>
<!-- Button label to remove the work profile [CHAR LIMIT=35] -->
<string name="remove_managed_profile_label">Remove work profile</string>
<!-- Data synchronization settings screen, title of setting that controls whether background data should be used [CHAR LIMIT=30] -->
@@ -9779,6 +9775,8 @@
<string name="cross_profile_calendar_title">Cross-profile calendar</string>
<!-- [CHAR LIMIT=NONE] Setting description. If the user turns on this setting, they can see their work events on their personal calendar. -->
<string name="cross_profile_calendar_summary">Show work events on your personal calendar</string>
<!-- [CHAR_LIMIT_NONE] Footer description. Explains to the user what will happen when work apps are turned off. -->
<string name="managed_profile_settings_footer">When work apps are off, theyre paused and cant be accessed or send you notifications</string>
<!-- Used as title on the automatic storage manager settings. [CHAR LIMIT=60] -->
<string name="automatic_storage_manager_settings">Manage storage</string>

View File

@@ -19,10 +19,9 @@
android:key="managed_profile_settings_screen"
android:title="@string/managed_profile_settings_title">
<SwitchPreference
<com.android.settingslib.widget.MainSwitchPreference
android:key="work_mode"
android:title="@string/work_mode_label"
android:summary="@string/summary_placeholder"
settings:controller="com.android.settings.accounts.WorkModePreferenceController"/>
<com.android.settingslib.RestrictedSwitchPreference
@@ -38,4 +37,9 @@
android:title="@string/cross_profile_calendar_title"
settings:controller="com.android.settings.accounts.CrossProfileCalendarPreferenceController"/>
<com.android.settingslib.widget.FooterPreference
android:title="@string/managed_profile_settings_footer"
android:key="managed_profile_footer"
settings:searchable="false"/>
</PreferenceScreen>

View File

@@ -20,37 +20,38 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.slices.SliceData;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedSwitchPreference;
public class ContactSearchPreferenceController extends BasePreferenceController implements
Preference.OnPreferenceChangeListener {
import org.jetbrains.annotations.NotNull;
private UserHandle mManagedUser;
public class ContactSearchPreferenceController extends TogglePreferenceController implements
Preference.OnPreferenceChangeListener, DefaultLifecycleObserver,
ManagedProfileQuietModeEnabler.QuietModeChangeListener {
private final ManagedProfileQuietModeEnabler mQuietModeEnabler;
private final UserHandle mManagedUser;
private Preference mPreference;
public ContactSearchPreferenceController(Context context, String key) {
super(context, key);
// Set default managed profile for the current user, otherwise isAvailable will be false and
// the setting won't be searchable.
UserManager userManager = context.getSystemService(UserManager.class);
mManagedUser = Utils.getManagedProfile(userManager);
}
@VisibleForTesting
void setManagedUser(UserHandle managedUser) {
mManagedUser = managedUser;
mManagedUser = Utils.getManagedProfile(context.getSystemService(UserManager.class));
mQuietModeEnabler = new ManagedProfileQuietModeEnabler(context, this);
}
@Override
public int getAvailabilityStatus() {
return (mManagedUser != null) ? AVAILABLE : DISABLED_FOR_USER;
return mQuietModeEnabler.isAvailable() ? AVAILABLE : DISABLED_FOR_USER;
}
@Override
@@ -59,6 +60,7 @@ public class ContactSearchPreferenceController extends BasePreferenceController
if (preference instanceof RestrictedSwitchPreference) {
final RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
pref.setChecked(isChecked());
pref.setEnabled(!mQuietModeEnabler.isQuietModeEnabled());
if (mManagedUser != null) {
final RestrictedLockUtils.EnforcedAdmin enforcedAdmin =
RestrictedLockUtilsInternal.checkIfRemoteContactSearchDisallowed(
@@ -68,26 +70,48 @@ public class ContactSearchPreferenceController extends BasePreferenceController
}
}
private boolean isChecked() {
if (mManagedUser == null) {
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
updateState(mPreference);
}
@Override
public void onStart(@NotNull LifecycleOwner lifecycleOwner) {
lifecycleOwner.getLifecycle().addObserver(mQuietModeEnabler);
}
@Override
public void onStop(@NotNull LifecycleOwner lifecycleOwner) {
lifecycleOwner.getLifecycle().removeObserver(mQuietModeEnabler);
}
@Override
public boolean isChecked() {
if (mManagedUser == null || mQuietModeEnabler.isQuietModeEnabled()) {
return false;
}
return 0 != Settings.Secure.getIntForUser(mContext.getContentResolver(),
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, mManagedUser.getIdentifier());
}
private boolean setChecked(boolean isChecked) {
if (mManagedUser != null) {
final int value = isChecked ? 1 : 0;
Settings.Secure.putIntForUser(mContext.getContentResolver(),
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, value, mManagedUser.getIdentifier());
@Override
public boolean setChecked(boolean isChecked) {
if (mManagedUser == null || mQuietModeEnabler.isQuietModeEnabled()) {
return false;
}
final int value = isChecked ? 1 : 0;
Settings.Secure.putIntForUser(mContext.getContentResolver(),
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, value, mManagedUser.getIdentifier());
return true;
}
@Override
public final boolean onPreferenceChange(Preference preference, Object newValue) {
return setChecked((boolean) newValue);
public void onQuietModeChanged() {
if (mPreference != null) {
updateState(mPreference);
}
}
@Override
@@ -95,4 +119,9 @@ public class ContactSearchPreferenceController extends BasePreferenceController
public int getSliceType() {
return SliceData.SliceType.SWITCH;
}
}
@Override
public int getSliceHighlightMenuRes() {
return R.string.menu_key_accounts;
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2023 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.settings.accounts;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import com.android.settings.Utils;
import javax.annotation.Nullable;
/**
* A class that controls the managed profile's quiet mode, listens to quiet mode changes and
* modifies managed profile settings. The user facing term for quiet mode is "work apps".
*/
final class ManagedProfileQuietModeEnabler implements DefaultLifecycleObserver {
private static final String TAG = "QuietModeEnabler";
private final Context mContext;
private final QuietModeChangeListener mListener;
@Nullable private final UserHandle mManagedProfile;
private final UserManager mUserManager;
public interface QuietModeChangeListener {
/** Called when quiet mode has changed. */
void onQuietModeChanged();
}
ManagedProfileQuietModeEnabler(Context context, QuietModeChangeListener listener) {
mContext = context;
mListener = listener;
mUserManager = context.getSystemService(UserManager.class);
mManagedProfile = Utils.getManagedProfile(mUserManager);
}
public void setQuietModeEnabled(boolean enabled) {
if (mManagedProfile != null) {
mUserManager.requestQuietModeEnabled(enabled, mManagedProfile);
}
}
public boolean isQuietModeEnabled() {
return mManagedProfile != null && mUserManager.isQuietModeEnabled(mManagedProfile);
}
@Override
public void onStart(@NonNull LifecycleOwner owner) {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
mContext.registerReceiver(mReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED);
}
@Override
public void onStop(@NonNull LifecycleOwner owner) {
mContext.unregisterReceiver(mReceiver);
}
public boolean isAvailable() {
return (mManagedProfile != null);
}
private void refreshQuietMode() {
if (mListener != null) {
mListener.onQuietModeChanged();
}
}
/**
* Receiver that listens to {@link Intent#ACTION_MANAGED_PROFILE_AVAILABLE} and
* {@link Intent#ACTION_MANAGED_PROFILE_UNAVAILABLE}, and updates the work mode
*/
@VisibleForTesting
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
return;
}
String action = intent.getAction();
Log.v(TAG, "Received broadcast: " + action);
if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
|| Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
int intentUserIdentifier = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL);
if (intentUserIdentifier == mManagedProfile.getIdentifier()) {
refreshQuietMode();
} else {
Log.w(TAG, "Managed profile broadcast ID: " + intentUserIdentifier
+ " does not match managed user: " + mManagedProfile);
}
} else {
Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
}
}
};
}

View File

@@ -1,165 +1,90 @@
/*
* Copyright (C) 2018 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
* 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.
* 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.settings.accounts;
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SETTING_OFF_SUMMARY;
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SETTING_ON_SUMMARY;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.preference.TwoStatePreference;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.slices.SliceData;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settings.widget.SettingsMainSwitchPreferenceController;
import com.android.settingslib.widget.MainSwitchPreference;
public class WorkModePreferenceController extends BasePreferenceController implements
Preference.OnPreferenceChangeListener, LifecycleObserver, OnStart, OnStop {
import org.jetbrains.annotations.NotNull;
private static final String TAG = "WorkModeController";
private UserManager mUserManager;
private UserHandle mManagedUser;
private DevicePolicyManager mDevicePolicyManager;
public class WorkModePreferenceController extends SettingsMainSwitchPreferenceController
implements Preference.OnPreferenceChangeListener, DefaultLifecycleObserver,
ManagedProfileQuietModeEnabler.QuietModeChangeListener {
private Preference mPreference;
private IntentFilter mIntentFilter;
private final ManagedProfileQuietModeEnabler mQuietModeEnabler;
public WorkModePreferenceController(Context context, String key) {
super(context, key);
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
mIntentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
// Set default managed profile for the current user, otherwise isAvailable will be false and
// the setting won't be searchable.
mManagedUser = Utils.getManagedProfile(mUserManager);
}
@VisibleForTesting
void setManagedUser(UserHandle managedUser) {
mManagedUser = managedUser;
}
@Override
public void onStart() {
mContext.registerReceiver(mReceiver, mIntentFilter,
Context.RECEIVER_EXPORTED_UNAUDITED);
}
@Override
public void onStop() {
mContext.unregisterReceiver(mReceiver);
mQuietModeEnabler = new ManagedProfileQuietModeEnabler(context, this);
}
@Override
public int getAvailabilityStatus() {
return (mManagedUser != null) ? AVAILABLE : DISABLED_FOR_USER;
return (mQuietModeEnabler.isAvailable()) ? AVAILABLE : DISABLED_FOR_USER;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
public void onStart(@NotNull LifecycleOwner lifecycleOwner) {
lifecycleOwner.getLifecycle().addObserver(mQuietModeEnabler);
}
@Override
public CharSequence getSummary() {
if (isChecked()) {
return mDevicePolicyManager.getResources().getString(
WORK_PROFILE_SETTING_ON_SUMMARY,
() -> mContext.getString(R.string.work_mode_on_summary));
}
return mDevicePolicyManager.getResources().getString(
WORK_PROFILE_SETTING_OFF_SUMMARY,
() -> mContext.getString(R.string.work_mode_off_summary));
public void onStop(@NotNull LifecycleOwner lifecycleOwner) {
lifecycleOwner.getLifecycle().removeObserver(mQuietModeEnabler);
}
private boolean isChecked() {
boolean isWorkModeOn = false;
if (mUserManager != null && mManagedUser != null) {
isWorkModeOn = !mUserManager.isQuietModeEnabled(mManagedUser);
}
return isWorkModeOn;
@Override
public boolean isChecked() {
return !mQuietModeEnabler.isQuietModeEnabled();
}
private boolean setChecked(boolean isChecked) {
if (mUserManager != null && mManagedUser != null) {
final boolean quietModeEnabled = !isChecked;
mUserManager.requestQuietModeEnabled(quietModeEnabled, mManagedUser);
}
@Override
public boolean setChecked(boolean isChecked) {
mQuietModeEnabler.setQuietModeEnabled(!isChecked);
return true;
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
if (preference instanceof TwoStatePreference) {
((TwoStatePreference) preference).setChecked(isChecked());
}
public void onQuietModeChanged() {
updateState(mSwitchPreference);
}
@Override
public final boolean onPreferenceChange(Preference preference, Object newValue) {
return setChecked((boolean) newValue);
}
/**
* Receiver that listens to {@link Intent#ACTION_MANAGED_PROFILE_AVAILABLE} and
* {@link Intent#ACTION_MANAGED_PROFILE_UNAVAILABLE}, and updates the work mode
*/
@VisibleForTesting
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
return;
}
final String action = intent.getAction();
Log.v(TAG, "Received broadcast: " + action);
if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
|| Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
if (intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL) == mManagedUser.getIdentifier()) {
updateState(mPreference);
}
return;
}
Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
}
};
@Override
@SliceData.SliceType
public int getSliceType() {
return SliceData.SliceType.SWITCH;
}
}
@Override
public int getSliceHighlightMenuRes() {
return R.string.menu_key_accounts;
}
@VisibleForTesting
void setPreference(MainSwitchPreference preference) {
mSwitchPreference = preference;
}
}

View File

@@ -20,13 +20,19 @@ import static android.provider.Settings.Secure.MANAGED_PROFILE_CONTACT_REMOTE_SE
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import com.android.settingslib.RestrictedSwitchPreference;
import org.junit.Before;
@@ -35,39 +41,51 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.Collections;
@RunWith(RobolectricTestRunner.class)
public class ContactSearchPreferenceControllerTest {
private static final String PREF_KEY = "contacts_search";
@Mock
private UserHandle mManagedUser;
private static final int MANAGED_USER_ID = 10;
private Context mContext;
private ContactSearchPreferenceController mController;
private RestrictedSwitchPreference mPreference;
@Mock
private UserHandle mManagedUser;
@Mock
private UserManager mUserManager;
@Mock
private UserInfo mUserInfo;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mController = new ContactSearchPreferenceController(mContext, PREF_KEY);
mController.setManagedUser(mManagedUser);
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
mPreference = spy(new RestrictedSwitchPreference(mContext));
when(mUserInfo.isManagedProfile()).thenReturn(true);
when(mUserManager.getUserInfo(anyInt())).thenReturn(mUserInfo);
when(mUserManager.getProcessUserId()).thenReturn(0);
when(mUserManager.getUserProfiles()).thenReturn(Collections.singletonList(mManagedUser));
when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
mController = new ContactSearchPreferenceController(mContext, PREF_KEY);
}
@Test
public void getAvailabilityStatus_noManagedUser_DISABLED() {
mController.setManagedUser(null);
when(mUserManager.getProcessUserId()).thenReturn(MANAGED_USER_ID);
mController = new ContactSearchPreferenceController(mContext, PREF_KEY);
assertThat(mController.getAvailabilityStatus())
.isNotEqualTo(ContactSearchPreferenceController.AVAILABLE);
}
@Test
public void getAvailabilityStatus_hasManagedUser_AVAILABLE() {
mController.setManagedUser(mManagedUser);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(ContactSearchPreferenceController.AVAILABLE);
}
@@ -75,32 +93,96 @@ public class ContactSearchPreferenceControllerTest {
@Test
public void updateState_shouldRefreshContent() {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, mManagedUser.getIdentifier());
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, MANAGED_USER_ID);
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isFalse();
Settings.Secure.putIntForUser(mContext.getContentResolver(),
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, mManagedUser.getIdentifier());
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, MANAGED_USER_ID);
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void updateState_preferenceShouldBeDisabled() {
mController.updateState(mPreference);
verify(mPreference).setDisabledByAdmin(any());
}
@Test
public void onPreferenceChange_shouldUpdateProviderValue() {
mController.onPreferenceChange(mPreference, false);
assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, mManagedUser.getIdentifier()))
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, MANAGED_USER_ID))
.isEqualTo(0);
mController.onPreferenceChange(mPreference, true);
assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, mManagedUser.getIdentifier()))
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, MANAGED_USER_ID))
.isEqualTo(1);
}
}
@Test
public void onQuietModeDisabled_preferenceEnabled() {
when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isTrue();
}
@Test
public void onQuietModeEnabled_preferenceDisabledAndUnchecked() {
when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(true);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isFalse();
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void afterQuietModeTurnedOnAndOffWhenPreferenceChecked_toggleCheckedAndEnabled() {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, MANAGED_USER_ID);
when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(true);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isFalse();
assertThat(mPreference.isChecked()).isFalse();
when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isTrue();
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void afterQuietModeTurnedOnAndOffWhenPreferenceUnchecked_toggleUncheckedAndEnabled() {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, MANAGED_USER_ID);
when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(true);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isFalse();
assertThat(mPreference.isChecked()).isFalse();
when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isTrue();
assertThat(mPreference.isChecked()).isFalse();
}
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2023 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.settings.accounts;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import java.util.Collections;
@RunWith(RobolectricTestRunner.class)
public class ManagedProfileQuietModeEnablerTest {
private static final int MANAGED_USER_ID = 10;
private Context mContext;
private ManagedProfileQuietModeEnabler mQuietModeEnabler;
private LifecycleOwner mLifecycleOwner = new LifecycleOwner() {
public LifecycleRegistry registry = new LifecycleRegistry(this);
@Override
public Lifecycle getLifecycle() {
return registry;
}
};
@Mock
private ManagedProfileQuietModeEnabler.QuietModeChangeListener mOnQuietModeChangeListener;
@Mock
private UserManager mUserManager;
@Mock
private UserHandle mManagedUser;
@Mock
private UserInfo mUserInfo;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
when(mUserInfo.isManagedProfile()).thenReturn(true);
when(mUserManager.getUserInfo(anyInt())).thenReturn(mUserInfo);
when(mUserManager.getProcessUserId()).thenReturn(0);
when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
when(mUserManager.getUserProfiles()).thenReturn(Collections.singletonList(mManagedUser));
mQuietModeEnabler = new ManagedProfileQuietModeEnabler(mContext,
mOnQuietModeChangeListener);
}
@Test
public void onSetQuietMode_shouldRequestQuietModeEnabled() {
mQuietModeEnabler.setQuietModeEnabled(false);
verify(mUserManager).requestQuietModeEnabled(false, mManagedUser);
mQuietModeEnabler.setQuietModeEnabled(true);
verify(mUserManager).requestQuietModeEnabled(true, mManagedUser);
}
@Test
public void onIsQuietModeEnabled_shouldCallIsQuietModeEnabled() {
assertThat(mQuietModeEnabler.isQuietModeEnabled()).isEqualTo(
verify(mUserManager).isQuietModeEnabled(any()));
}
@Test
public void onQuietModeChanged_listenerNotified() {
mQuietModeEnabler.onStart(mLifecycleOwner);
mContext.sendBroadcast(new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE).putExtra(
Intent.EXTRA_USER_HANDLE, MANAGED_USER_ID));
mContext.sendBroadcast(new Intent(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE).putExtra(
Intent.EXTRA_USER_HANDLE, MANAGED_USER_ID));
verify(mOnQuietModeChangeListener, times(2)).onQuietModeChanged();
}
@Test
public void onStart_shouldRegisterReceiver() {
mQuietModeEnabler.onStart(mLifecycleOwner);
verify(mContext).registerReceiver(eq(mQuietModeEnabler.mReceiver), any(), anyInt());
}
@Test
public void onStop_shouldUnregisterReceiver() {
// register it first
mContext.registerReceiver(mQuietModeEnabler.mReceiver, null,
Context.RECEIVER_EXPORTED/*UNAUDITED*/);
mQuietModeEnabler.onStop(mLifecycleOwner);
verify(mContext).unregisterReceiver(mQuietModeEnabler.mReceiver);
}
}

View File

@@ -19,18 +19,18 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settingslib.widget.MainSwitchPreference;
import org.junit.Before;
import org.junit.Test;
@@ -38,43 +38,51 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.Collections;
@RunWith(RobolectricTestRunner.class)
public class WorkModePreferenceControllerTest {
private static final String PREF_KEY = "work_mode";
private static final int MANAGED_USER_ID = 10;
private Context mContext;
private WorkModePreferenceController mController;
private MainSwitchPreference mPreference;
@Mock
private UserManager mUserManager;
@Mock
private UserHandle mManagedUser;
private Context mContext;
private WorkModePreferenceController mController;
private SwitchPreference mPreference;
@Mock
private UserInfo mUserInfo;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
mPreference = new MainSwitchPreference(mContext);
when(mUserInfo.isManagedProfile()).thenReturn(true);
when(mUserManager.getUserInfo(anyInt())).thenReturn(mUserInfo);
when(mUserManager.getProcessUserId()).thenReturn(0);
when(mUserManager.getUserProfiles()).thenReturn(Collections.singletonList(mManagedUser));
when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
mController = new WorkModePreferenceController(mContext, PREF_KEY);
mController.setManagedUser(mManagedUser);
mPreference = new SwitchPreference(mContext);
}
@Test
public void getAvailabilityStatus_noManagedUser_DISABLED() {
mController.setManagedUser(null);
when(mUserManager.getProcessUserId()).thenReturn(MANAGED_USER_ID);
mController = new WorkModePreferenceController(mContext, PREF_KEY);
assertThat(mController.getAvailabilityStatus())
.isNotEqualTo(WorkModePreferenceController.AVAILABLE);
}
@Test
public void getAvailabilityStatus_hasManagedUser_AVAILABLE() {
mController.setManagedUser(mManagedUser);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(WorkModePreferenceController.AVAILABLE);
}
@@ -83,41 +91,29 @@ public class WorkModePreferenceControllerTest {
public void updateState_shouldRefreshContent() {
when(mUserManager.isQuietModeEnabled(any(UserHandle.class)))
.thenReturn(false);
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isTrue();
assertThat(mPreference.getSummary())
.isEqualTo(mContext.getText(R.string.work_mode_on_summary));
when(mUserManager.isQuietModeEnabled(any(UserHandle.class)))
.thenReturn(true);
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isFalse();
assertThat(mPreference.getSummary())
.isEqualTo(mContext.getText(R.string.work_mode_off_summary));
}
@Test
public void onPreferenceChange_shouldRequestQuietModeEnabled() {
mController.setPreference(mPreference);
mController.onPreferenceChange(mPreference, true);
verify(mUserManager).requestQuietModeEnabled(false, mManagedUser);
mController.onPreferenceChange(mPreference, false);
verify(mUserManager).requestQuietModeEnabled(true, mManagedUser);
}
@Test
public void onStart_shouldRegisterReceiver() {
mController.onStart();
verify(mContext).registerReceiver(eq(mController.mReceiver), any(), anyInt());
}
@Test
public void onStop_shouldUnregisterReceiver() {
// register it first
mContext.registerReceiver(mController.mReceiver, null,
Context.RECEIVER_EXPORTED/*UNAUDITED*/);
mController.onStop();
verify(mContext).unregisterReceiver(mController.mReceiver);
}
}