diff --git a/res/values/strings.xml b/res/values/strings.xml index a87ba4ca328..aef7fc48538 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1101,6 +1101,8 @@ Name OK + + Try again Delete @@ -1257,9 +1259,9 @@ Touch the sensor on the back of your phone. Use your index finger. - Enrollment was not completed + Fingerprint setup timed out - Fingerprint enrollment time limit reached. Try again. + Try again now or set up your fingerprint later in Settings Fingerprint enrollment didn\'t work. Try again or use a different finger. @@ -7704,17 +7706,15 @@ Apps and data from this guest session will be deleted now, and all future guest activity will be deleted each time you exit guest mode + + Allow guest to use phone + + Call history will be shared with guest user - - Turn on phone calls Turn on phone calls & SMS Delete user - - Turn on phone calls? - - Call history will be shared with this user. Turn on phone calls & SMS? diff --git a/res/xml/user_settings.xml b/res/xml/user_settings.xml index 5cbfe4306eb..8a5a4ef0552 100644 --- a/res/xml/user_settings.xml +++ b/res/xml/user_settings.xml @@ -78,6 +78,13 @@ android:summary="@string/remove_guest_on_exit_summary" android:order="60"/> + + subInfo.getSubscriptionId() == subId) .findFirst() - .get(); + .orElse(null); } /** diff --git a/src/com/android/settings/network/SwitchToEuiccSubscriptionSidecar.java b/src/com/android/settings/network/SwitchToEuiccSubscriptionSidecar.java index 935e235aeaf..4eee6053da8 100644 --- a/src/com/android/settings/network/SwitchToEuiccSubscriptionSidecar.java +++ b/src/com/android/settings/network/SwitchToEuiccSubscriptionSidecar.java @@ -21,6 +21,8 @@ import android.app.PendingIntent; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.UiccCardInfo; +import android.telephony.UiccPortInfo; +import android.telephony.UiccSlotInfo; import android.telephony.UiccSlotMapping; import android.telephony.euicc.EuiccManager; import android.util.Log; @@ -28,6 +30,8 @@ import android.util.Log; import com.android.settings.SidecarFragment; import com.android.settings.network.telephony.EuiccOperationSidecar; +import com.google.common.collect.ImmutableList; + import java.util.Collection; import java.util.Comparator; import java.util.List; @@ -44,6 +48,7 @@ public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar { private int mPort; private SubscriptionInfo mRemovedSubInfo; private boolean mIsDuringSimSlotMapping; + private List mActiveSubInfos; /** Returns a SwitchToEuiccSubscriptionSidecar sidecar instance. */ public static SwitchToEuiccSubscriptionSidecar get(FragmentManager fm) { @@ -87,6 +92,10 @@ public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar { setState(State.RUNNING, Substate.UNUSED); mCallbackIntent = createCallbackIntent(); mSubId = subscriptionId; + SubscriptionManager subscriptionManager = getContext().getSystemService( + SubscriptionManager.class); + mActiveSubInfos = SubscriptionUtil.getActiveSubscriptions(subscriptionManager); + int targetSlot = getTargetSlot(); if (targetSlot < 0) { Log.d(TAG, "There is no esim, the TargetSlot is " + targetSlot); @@ -99,15 +108,29 @@ public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar { mPort = (port < 0) ? getTargetPortId(targetSlot, removedSubInfo) : port; mRemovedSubInfo = removedSubInfo; Log.d(TAG, - String.format("set esim into the SubId%d Slot%d:Port%d", + String.format("set esim into the SubId%d Physical Slot%d:Port%d", mSubId, targetSlot, mPort)); - - if (mTelephonyManager.isMultiSimEnabled() && removedSubInfo != null - && removedSubInfo.isEmbedded()) { - // In DSDS mode+MEP, if the replaced esim is active, then it should be disabled esim - // profile before changing SimSlotMapping process. - // Use INVALID_SUBSCRIPTION_ID to disable the esim profile. - // The SimSlotMapping is ready, then to execute activate/inactivate esim. + if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + // If the subId is INVALID_SUBSCRIPTION_ID, disable the esim (the default esim slot + // which is selected by the framework). + switchToSubscription(); + } else if ((mTelephonyManager.isMultiSimEnabled() && removedSubInfo != null + && removedSubInfo.isEmbedded()) + || isEsimEnabledAtTargetSlotPort(targetSlot, mPort)) { + // Case1: In DSDS mode+MEP, if the replaced esim is active, then the replaced esim + // should be disabled before changing SimSlotMapping process. + // + // Case2: If the user enables the esimA on the target slot:port and the target + // slot:port is active and there is an active esimB on target slot:port, then the + // settings disables the esimB before the settings enables the esimA on the + // target slot:port. + // + // Step: + // 1. disables the replaced esim. + // 2. switches the SimSlotMapping if the target slot port is not active. + // 3. enables the target esim. + // Note: Use INVALID_SUBSCRIPTION_ID to disable the esim profile. + Log.d(TAG, "disable the enabled esim before the settings enables the target esim"); mIsDuringSimSlotMapping = true; mEuiccManager.switchToSubscription(SubscriptionManager.INVALID_SUBSCRIPTION_ID, mPort, mCallbackIntent); @@ -117,8 +140,8 @@ public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar { } private int getTargetPortId(int physicalEsimSlotIndex, SubscriptionInfo removedSubInfo) { - if (!isMultipleEnabledProfilesSupported()) { - Log.d(TAG, "The device is no MEP, port is 0"); + if (!isMultipleEnabledProfilesSupported(physicalEsimSlotIndex)) { + Log.d(TAG, "The slotId" + physicalEsimSlotIndex + " is no MEP, port is 0"); return 0; } @@ -150,11 +173,12 @@ public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar { // port is 0. int port = 0; - SubscriptionManager subscriptionManager = getContext().getSystemService( - SubscriptionManager.class); + if(mActiveSubInfos == null){ + Log.d(TAG, "mActiveSubInfos is null."); + return port; + } List activeEsimSubInfos = - SubscriptionUtil.getActiveSubscriptions(subscriptionManager) - .stream() + mActiveSubInfos.stream() .filter(i -> i.isEmbedded()) .sorted(Comparator.comparingInt(SubscriptionInfo::getPortIndex)) .collect(Collectors.toList()); @@ -167,7 +191,31 @@ public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar { } private int getTargetSlot() { - return UiccSlotUtil.getEsimSlotId(getContext()); + return UiccSlotUtil.getEsimSlotId(getContext(), mSubId); + } + + private boolean isEsimEnabledAtTargetSlotPort(int physicalSlotIndex, int portIndex) { + int logicalSlotId = getLogicalSlotIndex(physicalSlotIndex, portIndex); + if (logicalSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { + return false; + } + return mActiveSubInfos != null + && mActiveSubInfos.stream() + .anyMatch(i -> i.isEmbedded() && i.getSimSlotIndex() == logicalSlotId); + } + + private int getLogicalSlotIndex(int physicalSlotIndex, int portIndex) { + ImmutableList slotInfos = UiccSlotUtil.getSlotInfos(mTelephonyManager); + if (slotInfos != null && physicalSlotIndex >= 0 && physicalSlotIndex < slotInfos.size() + && slotInfos.get(physicalSlotIndex) != null) { + for (UiccPortInfo portInfo : slotInfos.get(physicalSlotIndex).getPorts()) { + if (portInfo.getPortIndex() == portIndex) { + return portInfo.getLogicalSlotIndex(); + } + } + } + + return SubscriptionManager.INVALID_SIM_SLOT_INDEX; } private void onSwitchSlotSidecarStateChange() { @@ -185,14 +233,15 @@ public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar { } } - private boolean isMultipleEnabledProfilesSupported() { + private boolean isMultipleEnabledProfilesSupported(int physicalEsimSlotIndex) { List cardInfos = mTelephonyManager.getUiccCardsInfo(); if (cardInfos == null) { Log.w(TAG, "UICC cards info list is empty."); return false; } - return cardInfos.stream().anyMatch( - cardInfo -> cardInfo.isMultipleEnabledProfilesSupported()); + return cardInfos.stream() + .anyMatch(cardInfo -> cardInfo.getPhysicalSlotIndex() == physicalEsimSlotIndex + && cardInfo.isMultipleEnabledProfilesSupported()); } private void switchToSubscription() { diff --git a/src/com/android/settings/network/UiccSlotUtil.java b/src/com/android/settings/network/UiccSlotUtil.java index c9c52cb5c99..7ba2e0f8ed0 100644 --- a/src/com/android/settings/network/UiccSlotUtil.java +++ b/src/com/android/settings/network/UiccSlotUtil.java @@ -22,11 +22,13 @@ import android.provider.Settings; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.UiccCardInfo; import android.telephony.UiccSlotInfo; import android.telephony.UiccSlotMapping; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.uicc.UiccController; import com.android.settingslib.utils.ThreadUtils; import com.google.common.collect.ImmutableList; @@ -36,6 +38,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -183,9 +186,27 @@ public class UiccSlotUtil { * @param context the application context. * @return the esim slot. If the value is -1, there is not the esim. */ - public static int getEsimSlotId(Context context) { + public static int getEsimSlotId(Context context, int subId) { TelephonyManager telMgr = context.getSystemService(TelephonyManager.class); + List uiccCardInfos = telMgr.getUiccCardsInfo(); ImmutableList slotInfos = UiccSlotUtil.getSlotInfos(telMgr); + SubscriptionManager subscriptionManager = context.getSystemService( + SubscriptionManager.class); + SubscriptionInfo subInfo = SubscriptionUtil.getSubById(subscriptionManager, subId); + + // checking whether this is the removable esim. If it is, then return the removable slot id. + if (subInfo != null && subInfo.isEmbedded()) { + for (UiccCardInfo uiccCardInfo : uiccCardInfos) { + if (uiccCardInfo.getCardId() == subInfo.getCardId() + && uiccCardInfo.getCardId() > TelephonyManager.UNSUPPORTED_CARD_ID + && uiccCardInfo.isEuicc() + && uiccCardInfo.isRemovable()) { + Log.d(TAG, "getEsimSlotId: This subInfo is removable esim."); + return uiccCardInfo.getPhysicalSlotIndex(); + } + } + } + int firstEsimSlot = IntStream.range(0, slotInfos.size()) .filter( index -> { diff --git a/src/com/android/settings/sim/PreferredSimDialogFragment.java b/src/com/android/settings/sim/PreferredSimDialogFragment.java index 6b5e2b50f73..806e04b35bb 100644 --- a/src/com/android/settings/sim/PreferredSimDialogFragment.java +++ b/src/com/android/settings/sim/PreferredSimDialogFragment.java @@ -88,6 +88,11 @@ public class PreferredSimDialogFragment extends SimDialogFragment implements return; } + if (dialog == null) { + Log.d(TAG, "Dialog is null."); + dismiss(); + } + final SubscriptionInfo info = getPreferredSubscription(); if (info == null) { dismiss(); diff --git a/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java b/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java index 1f8417737fb..a989d520c20 100644 --- a/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java +++ b/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java @@ -100,6 +100,11 @@ public class SelectSpecificDataSimDialogFragment extends SimDialogFragment imple return; } + if (dialog == null) { + Log.d(TAG, "Dialog is null."); + dismiss(); + } + SubscriptionInfo currentDataSubInfo = getDefaultDataSubInfo(); SubscriptionInfo newSubInfo = getNonDefaultDataSubscriptionInfo(currentDataSubInfo); diff --git a/src/com/android/settings/users/GuestTelephonyPreferenceController.java b/src/com/android/settings/users/GuestTelephonyPreferenceController.java new file mode 100644 index 00000000000..a935b8a4535 --- /dev/null +++ b/src/com/android/settings/users/GuestTelephonyPreferenceController.java @@ -0,0 +1,78 @@ +/* + * 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.settings.users; + +import android.content.Context; +import android.os.Bundle; +import android.os.UserManager; + +import androidx.preference.Preference; + +import com.android.settings.R; +import com.android.settings.core.TogglePreferenceController; + +/** + * Controls the preference on the user settings screen which determines whether the guest user + * should have access to telephony or not. + */ +public class GuestTelephonyPreferenceController extends TogglePreferenceController { + + private final UserManager mUserManager; + private final UserCapabilities mUserCaps; + private Bundle mDefaultGuestRestrictions; + + public GuestTelephonyPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mUserManager = context.getSystemService(UserManager.class); + mUserCaps = UserCapabilities.create(context); + mDefaultGuestRestrictions = mUserManager.getDefaultGuestRestrictions(); + mDefaultGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true); + } + + @Override + public int getAvailabilityStatus() { + if (!mUserCaps.isAdmin() || !mUserCaps.mCanAddGuest) { + return DISABLED_FOR_USER; + } else { + return mUserCaps.mUserSwitcherEnabled ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + } + } + + @Override + public boolean isChecked() { + return !mDefaultGuestRestrictions.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS, false); + } + + @Override + public boolean setChecked(boolean isChecked) { + mDefaultGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, !isChecked); + mUserManager.setDefaultGuestRestrictions(mDefaultGuestRestrictions); + return true; + } + + @Override + public int getSliceHighlightMenuRes() { + return R.string.menu_key_system; + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + mUserCaps.updateAddUserCapabilities(mContext); + preference.setVisible(isAvailable() && mUserCaps.mUserSwitcherEnabled); + } +} diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java index 3f51b83b9d7..dc6fbd4a50b 100644 --- a/src/com/android/settings/users/UserDetailsSettings.java +++ b/src/com/android/settings/users/UserDetailsSettings.java @@ -42,7 +42,6 @@ import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.RestrictedPreference; -import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; @@ -69,11 +68,10 @@ public class UserDetailsSettings extends SettingsPreferenceFragment static final String EXTRA_USER_ID = "user_id"; private static final int DIALOG_CONFIRM_REMOVE = 1; - private static final int DIALOG_CONFIRM_ENABLE_CALLING = 2; - private static final int DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS = 3; - private static final int DIALOG_SETUP_USER = 4; - private static final int DIALOG_CONFIRM_RESET_GUEST = 5; - private static final int DIALOG_CONFIRM_RESET_GUEST_AND_SWITCH_USER = 6; + private static final int DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS = 2; + private static final int DIALOG_SETUP_USER = 3; + private static final int DIALOG_CONFIRM_RESET_GUEST = 4; + private static final int DIALOG_CONFIRM_RESET_GUEST_AND_SWITCH_USER = 5; /** Whether to enable the app_copying fragment. */ private static final boolean SHOW_APP_COPYING_PREF = false; @@ -97,7 +95,6 @@ public class UserDetailsSettings extends SettingsPreferenceFragment @VisibleForTesting /** The user being studied (not the user doing the studying). */ UserInfo mUserInfo; - private Bundle mDefaultGuestRestrictions; @Override public int getMetricsCategory() { @@ -165,12 +162,13 @@ public class UserDetailsSettings extends SettingsPreferenceFragment @Override public boolean onPreferenceChange(Preference preference, Object newValue) { - if (Boolean.TRUE.equals(newValue)) { - showDialog(mUserInfo.isGuest() ? DIALOG_CONFIRM_ENABLE_CALLING - : DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS); - return false; + if (preference == mPhonePref) { + if (Boolean.TRUE.equals(newValue)) { + showDialog(DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS); + return false; + } + enableCallsAndSms(false); } - enableCallsAndSms(false); return true; } @@ -181,8 +179,6 @@ public class UserDetailsSettings extends SettingsPreferenceFragment case DIALOG_CONFIRM_RESET_GUEST: case DIALOG_CONFIRM_RESET_GUEST_AND_SWITCH_USER: return SettingsEnums.DIALOG_USER_REMOVE; - case DIALOG_CONFIRM_ENABLE_CALLING: - return SettingsEnums.DIALOG_USER_ENABLE_CALLING; case DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS: return SettingsEnums.DIALOG_USER_ENABLE_CALLING_AND_SMS; case DIALOG_SETUP_USER: @@ -202,9 +198,6 @@ public class UserDetailsSettings extends SettingsPreferenceFragment case DIALOG_CONFIRM_REMOVE: return UserDialogs.createRemoveDialog(getActivity(), mUserInfo.id, (dialog, which) -> removeUser()); - case DIALOG_CONFIRM_ENABLE_CALLING: - return UserDialogs.createEnablePhoneCallsDialog(getActivity(), - (dialog, which) -> enableCallsAndSms(true)); case DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS: return UserDialogs.createEnablePhoneCallsAndSmsDialog(getActivity(), (dialog, which) -> enableCallsAndSms(true)); @@ -308,13 +301,7 @@ public class UserDetailsSettings extends SettingsPreferenceFragment } if (mUserInfo.isGuest()) { - // These are not for an existing user, just general Guest settings. - // Default title is for calling and SMS. Change to calling-only here - // TODO(b/191483069): These settings can't be changed unless guest user exists - mPhonePref.setTitle(R.string.user_enable_calling); - mDefaultGuestRestrictions = mUserManager.getDefaultGuestRestrictions(); - mPhonePref.setChecked( - !mDefaultGuestRestrictions.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + removePreference(KEY_ENABLE_TELEPHONY); mRemoveUserPref.setTitle(mGuestUserAutoCreated ? com.android.settingslib.R.string.guest_reset_guest : com.android.settingslib.R.string.guest_exit_guest); @@ -397,31 +384,9 @@ public class UserDetailsSettings extends SettingsPreferenceFragment private void enableCallsAndSms(boolean enabled) { mPhonePref.setChecked(enabled); - if (mUserInfo.isGuest()) { - mDefaultGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, !enabled); - // SMS is always disabled for guest - mDefaultGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true); - mUserManager.setDefaultGuestRestrictions(mDefaultGuestRestrictions); - - // Update the guest's restrictions, if there is a guest - // TODO: Maybe setDefaultGuestRestrictions() can internally just set the restrictions - // on any existing guest rather than do it here with multiple Binder calls. - List users = mUserManager.getAliveUsers(); - for (UserInfo user : users) { - if (user.isGuest()) { - UserHandle userHandle = UserHandle.of(user.id); - for (String key : mDefaultGuestRestrictions.keySet()) { - mUserManager.setUserRestriction( - key, mDefaultGuestRestrictions.getBoolean(key), userHandle); - } - } - } - } else { - UserHandle userHandle = UserHandle.of(mUserInfo.id); - mUserManager.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, !enabled, - userHandle); - mUserManager.setUserRestriction(UserManager.DISALLOW_SMS, !enabled, userHandle); - } + UserHandle userHandle = UserHandle.of(mUserInfo.id); + mUserManager.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, !enabled, userHandle); + mUserManager.setUserRestriction(UserManager.DISALLOW_SMS, !enabled, userHandle); } private void removeUser() { diff --git a/src/com/android/settings/users/UserDialogs.java b/src/com/android/settings/users/UserDialogs.java index faaff4c118e..c2f2528530b 100644 --- a/src/com/android/settings/users/UserDialogs.java +++ b/src/com/android/settings/users/UserDialogs.java @@ -145,21 +145,6 @@ public final class UserDialogs { .create(); } - /** - * Creates a dialog to confirm that the user is ok to enable phone calls (no SMS). - * - * @param onConfirmListener Callback object for positive action - */ - public static Dialog createEnablePhoneCallsDialog(Context context, - DialogInterface.OnClickListener onConfirmListener) { - return new AlertDialog.Builder(context) - .setTitle(R.string.user_enable_calling_confirm_title) - .setMessage(R.string.user_enable_calling_confirm_message) - .setPositiveButton(R.string.okay, onConfirmListener) - .setNegativeButton(android.R.string.cancel, null) - .create(); - } - /** * Creates a dialog to confirm that the user is ok to start setting up a new user. * diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java index ec11755d481..5b2729af414 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -125,6 +125,7 @@ public class UserSettings extends SettingsPreferenceFragment private static final String KEY_ADD_USER = "user_add"; private static final String KEY_ADD_SUPERVISED_USER = "supervised_user_add"; private static final String KEY_ADD_USER_WHEN_LOCKED = "user_settings_add_users_when_locked"; + private static final String KEY_ENABLE_GUEST_TELEPHONY = "enable_guest_calling"; private static final String KEY_MULTIUSER_TOP_INTRO = "multiuser_top_intro"; private static final String KEY_TIMEOUT_TO_USER_ZERO = "timeout_to_user_zero_preference"; private static final String KEY_GUEST_CATEGORY = "guest_category"; @@ -215,6 +216,7 @@ public class UserSettings extends SettingsPreferenceFragment private EditUserInfoController mEditUserInfoController = new EditUserInfoController(Utils.FILE_PROVIDER_AUTHORITY); private AddUserWhenLockedPreferenceController mAddUserWhenLockedPreferenceController; + private GuestTelephonyPreferenceController mGuestTelephonyPreferenceController; private RemoveGuestOnExitPreferenceController mRemoveGuestOnExitPreferenceController; private MultiUserTopIntroPreferenceController mMultiUserTopIntroPreferenceController; private TimeoutToUserZeroPreferenceController mTimeoutToUserZeroPreferenceController; @@ -310,6 +312,9 @@ public class UserSettings extends SettingsPreferenceFragment mAddUserWhenLockedPreferenceController = new AddUserWhenLockedPreferenceController( activity, KEY_ADD_USER_WHEN_LOCKED); + mGuestTelephonyPreferenceController = new GuestTelephonyPreferenceController( + activity, KEY_ENABLE_GUEST_TELEPHONY); + mRemoveGuestOnExitPreferenceController = new RemoveGuestOnExitPreferenceController( activity, KEY_REMOVE_GUEST_ON_EXIT, this, mHandler); @@ -321,6 +326,7 @@ public class UserSettings extends SettingsPreferenceFragment final PreferenceScreen screen = getPreferenceScreen(); mAddUserWhenLockedPreferenceController.displayPreference(screen); + mGuestTelephonyPreferenceController.displayPreference(screen); mRemoveGuestOnExitPreferenceController.displayPreference(screen); mMultiUserTopIntroPreferenceController.displayPreference(screen); mTimeoutToUserZeroPreferenceController.displayPreference(screen); @@ -328,6 +334,9 @@ public class UserSettings extends SettingsPreferenceFragment screen.findPreference(mAddUserWhenLockedPreferenceController.getPreferenceKey()) .setOnPreferenceChangeListener(mAddUserWhenLockedPreferenceController); + screen.findPreference(mGuestTelephonyPreferenceController.getPreferenceKey()) + .setOnPreferenceChangeListener(mGuestTelephonyPreferenceController); + screen.findPreference(mRemoveGuestOnExitPreferenceController.getPreferenceKey()) .setOnPreferenceChangeListener(mRemoveGuestOnExitPreferenceController); @@ -397,6 +406,8 @@ public class UserSettings extends SettingsPreferenceFragment mAddUserWhenLockedPreferenceController.updateState(screen.findPreference( mAddUserWhenLockedPreferenceController.getPreferenceKey())); + mGuestTelephonyPreferenceController.updateState(screen.findPreference( + mGuestTelephonyPreferenceController.getPreferenceKey())); mTimeoutToUserZeroPreferenceController.updateState(screen.findPreference( mTimeoutToUserZeroPreferenceController.getPreferenceKey())); mRemoveGuestOnExitPreferenceController.updateState(screen.findPreference( @@ -1302,9 +1313,13 @@ public class UserSettings extends SettingsPreferenceFragment mAddUserWhenLockedPreferenceController.getPreferenceKey()); mAddUserWhenLockedPreferenceController.updateState(addUserOnLockScreen); - final Preference multiUserTopIntroPrefence = getPreferenceScreen().findPreference( + final Preference guestCallPreference = getPreferenceScreen().findPreference( + mGuestTelephonyPreferenceController.getPreferenceKey()); + mGuestTelephonyPreferenceController.updateState(guestCallPreference); + + final Preference multiUserTopIntroPreference = getPreferenceScreen().findPreference( mMultiUserTopIntroPreferenceController.getPreferenceKey()); - mMultiUserTopIntroPreferenceController.updateState(multiUserTopIntroPrefence); + mMultiUserTopIntroPreferenceController.updateState(multiUserTopIntroPreference); mUserListCategory.setVisible(mUserCaps.mUserSwitcherEnabled); updateGuestPreferences(); updateGuestCategory(context, users); diff --git a/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java index c2a8611ec02..82c6b709076 100644 --- a/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/BrightnessLevelPreferenceControllerTest.java @@ -135,6 +135,21 @@ public class BrightnessLevelPreferenceControllerTest { System.getUriFor(System.SCREEN_AUTO_BRIGHTNESS_ADJ))).isEmpty(); } + @Test + public void onStart_shouldSetSummary() { + BrightnessLevelPreferenceController controller = + new BrightnessLevelPreferenceController(mContext, null); + controller.displayPreference(mScreen); + + controller.onStop(); + when(mDisplay.getBrightnessInfo()).thenReturn( + new BrightnessInfo(0.5f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, + 0.5f, BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE)); + controller.onStart(); + + verify(mPreference).setSummary("87%"); + } + @Test public void updateState_inVrMode_shouldSetSummaryToVrBrightness() { doReturn(true).when(mController).isInVrMode(); diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java index b865ea6ad15..90e098cf61a 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java @@ -47,7 +47,6 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager private static final int PRIMARY_USER_ID = 0; private final List mBaseRestrictions = new ArrayList<>(); - private final List mGuestRestrictions = new ArrayList<>(); private final Map> mRestrictionSources = new HashMap<>(); private final List mUserProfileInfos = new ArrayList<>(); private final Set mManagedProfiles = new HashSet<>(); @@ -55,6 +54,7 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager private boolean mIsQuietModeEnabled = false; private int[] profileIdsForUser = new int[0]; private boolean mUserSwitchEnabled; + private Bundle mDefaultGuestUserRestriction = new Bundle(); private @UserManager.UserSwitchabilityResult int mSwitchabilityStatus = UserManager.SWITCHABILITY_STATUS_OK; @@ -99,15 +99,24 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager @Implementation protected Bundle getDefaultGuestRestrictions() { - Bundle bundle = new Bundle(); - mGuestRestrictions.forEach(restriction -> bundle.putBoolean(restriction, true)); - return bundle; + return mDefaultGuestUserRestriction; + } + + @Implementation + protected void setDefaultGuestRestrictions(Bundle restrictions) { + mDefaultGuestUserRestriction = restrictions; } public void addGuestUserRestriction(String restriction) { - mGuestRestrictions.add(restriction); + mDefaultGuestUserRestriction.putBoolean(restriction, true); } + public boolean hasGuestUserRestriction(String restriction, boolean expectedValue) { + return mDefaultGuestUserRestriction.containsKey(restriction) + && mDefaultGuestUserRestriction.getBoolean(restriction) == expectedValue; + } + + @Implementation protected boolean hasUserRestriction(String restrictionKey) { return hasUserRestriction(restrictionKey, UserHandle.of(UserHandle.myUserId())); diff --git a/tests/robotests/src/com/android/settings/users/GuestTelephonyPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/users/GuestTelephonyPreferenceControllerTest.java new file mode 100644 index 00000000000..aa84cb66576 --- /dev/null +++ b/tests/robotests/src/com/android/settings/users/GuestTelephonyPreferenceControllerTest.java @@ -0,0 +1,150 @@ +/* + * 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.settings.users; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Answers.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.SystemProperties; +import android.os.UserManager; + +import androidx.preference.PreferenceScreen; + +import com.android.settings.testutils.shadow.ShadowDevicePolicyManager; +import com.android.settings.testutils.shadow.ShadowUserManager; +import com.android.settingslib.RestrictedSwitchPreference; + +import org.junit.After; +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 org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = { + ShadowUserManager.class, + ShadowDevicePolicyManager.class +}) +public class GuestTelephonyPreferenceControllerTest { + + @Mock(answer = RETURNS_DEEP_STUBS) + private PreferenceScreen mScreen; + + @Mock(answer = RETURNS_DEEP_STUBS) + private Context mContext; + private ShadowUserManager mUserManager; + private ShadowDevicePolicyManager mDpm; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mUserManager = ShadowUserManager.getShadow(); + mUserManager.setSupportsMultipleUsers(true); + mDpm = ShadowDevicePolicyManager.getShadow(); + } + + @After + public void tearDown() { + ShadowUserManager.reset(); + } + + @Test + public void displayPref_NotAdmin_shouldNotDisplay() { + mUserManager.setIsAdminUser(false); + + final GuestTelephonyPreferenceController controller = + new GuestTelephonyPreferenceController(mContext, "fake_key"); + final RestrictedSwitchPreference preference = mock(RestrictedSwitchPreference.class); + + when(preference.getKey()).thenReturn(controller.getPreferenceKey()); + when(mScreen.findPreference(preference.getKey())).thenReturn(preference); + + controller.displayPreference(mScreen); + + verify(preference).setVisible(false); + } + + @Test + public void updateState_NotAdmin_shouldNotDisplayPreference() { + mUserManager.setIsAdminUser(false); + + final GuestTelephonyPreferenceController controller = + new GuestTelephonyPreferenceController(mContext, "fake_key"); + final RestrictedSwitchPreference preference = mock(RestrictedSwitchPreference.class); + + controller.updateState(preference); + + verify(preference).setVisible(false); + } + + @Test + public void updateState_Admin_shouldDisplayPreference() { + SystemProperties.set("fw.max_users", Long.toBinaryString(4)); + mDpm.setDeviceOwner(null); + mUserManager.setIsAdminUser(true); + mUserManager.setUserSwitcherEnabled(true); + mUserManager.setSupportsMultipleUsers(true); + mUserManager.setUserTypeEnabled(UserManager.USER_TYPE_FULL_RESTRICTED, true); + mUserManager.setUserTypeEnabled(UserManager.USER_TYPE_FULL_SYSTEM, true); + mUserManager.setUserTypeEnabled(UserManager.USER_TYPE_FULL_GUEST, true); + + final GuestTelephonyPreferenceController controller = + new GuestTelephonyPreferenceController(mContext, "fake_key"); + final RestrictedSwitchPreference preference = mock(RestrictedSwitchPreference.class); + + controller.updateState(preference); + + verify(preference).setVisible(true); + } + + @Test + public void setChecked_Guest_hasNoCallRestriction() { + mUserManager.setIsAdminUser(true); + + final GuestTelephonyPreferenceController controller = + new GuestTelephonyPreferenceController(mContext, "fake_key"); + + controller.setChecked(true); + + assertThat(mUserManager.hasGuestUserRestriction("no_outgoing_calls", false)).isTrue(); + assertThat(mUserManager.hasGuestUserRestriction("no_sms", true)).isTrue(); + } + + @Test + public void setUnchecked_Guest_hasCallRestriction() { + mUserManager.setIsAdminUser(true); + + final GuestTelephonyPreferenceController controller = + new GuestTelephonyPreferenceController(mContext, "fake_key"); + + controller.setChecked(false); + + assertThat(mUserManager.hasGuestUserRestriction("no_outgoing_calls", true)).isTrue(); + assertThat(mUserManager.hasGuestUserRestriction("no_sms", true)).isTrue(); + } + +} diff --git a/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java b/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java index ccd2190db47..fad30aa01d4 100644 --- a/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java +++ b/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java @@ -420,29 +420,6 @@ public class UserDetailsSettingsTest { verify(mPhonePref).setChecked(true); } - @Test - public void initialize_guestSelected_noCallRestriction_shouldSetPhonePreference() { - setupSelectedGuest(); - mUserManager.setIsAdminUser(true); - - mFragment.initialize(mActivity, mArguments); - - verify(mPhonePref).setTitle(R.string.user_enable_calling); - verify(mPhonePref).setChecked(true); - } - - @Test - public void initialize_guestSelected_callRestriction_shouldSetPhonePreference() { - setupSelectedGuest(); - mUserManager.setIsAdminUser(true); - mUserManager.addGuestUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS); - - mFragment.initialize(mActivity, mArguments); - - verify(mPhonePref).setTitle(R.string.user_enable_calling); - verify(mPhonePref).setChecked(false); - } - @Test public void initialize_switchUserDisallowed_shouldSetAdminDisabledOnSwitchPreference() { setupSelectedUser(); diff --git a/tests/robotests/src/com/android/settings/users/UserSettingsTest.java b/tests/robotests/src/com/android/settings/users/UserSettingsTest.java index d1192c17fa0..1f8c0b40809 100644 --- a/tests/robotests/src/com/android/settings/users/UserSettingsTest.java +++ b/tests/robotests/src/com/android/settings/users/UserSettingsTest.java @@ -146,6 +146,8 @@ public class UserSettingsTest { mFragment = spy(new UserSettings()); ReflectionHelpers.setField(mFragment, "mAddUserWhenLockedPreferenceController", mock(AddUserWhenLockedPreferenceController.class)); + ReflectionHelpers.setField(mFragment, "mGuestTelephonyPreferenceController", + mock(GuestTelephonyPreferenceController.class)); ReflectionHelpers.setField(mFragment, "mMultiUserTopIntroPreferenceController", mock(MultiUserTopIntroPreferenceController.class)); ReflectionHelpers.setField(mFragment, "mUserManager", mUserManager); diff --git a/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java b/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java index 5aa73eaa308..526fc0c8d18 100644 --- a/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java +++ b/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java @@ -25,7 +25,9 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.UiccCardInfo; import android.telephony.UiccPortInfo; import android.telephony.UiccSlotInfo; import android.telephony.UiccSlotMapping; @@ -53,16 +55,24 @@ public class UiccSlotUtilTest { private Context mContext; @Mock private TelephonyManager mTelephonyManager; + @Mock + private SubscriptionManager mSubscriptionManager; private static final int ESIM_PHYSICAL_SLOT = 0; private static final int PSIM_PHYSICAL_SLOT = 1; + private List mSubscriptionInfoList = new ArrayList<>(); + private List mUiccCardInfo = new ArrayList<>(); @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(ApplicationProvider.getApplicationContext()); when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager); + when(mTelephonyManager.getUiccCardsInfo()).thenReturn(mUiccCardInfo); + + when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager); + when(mSubscriptionManager.getAllSubscriptionInfoList()).thenReturn(mSubscriptionInfoList); } @Test @@ -88,15 +98,35 @@ public class UiccSlotUtilTest { public void getEsimSlotId_twoSimSlotsDeviceAndEsimIsSlot0_returnTheCorrectEsimSlot() { when(mTelephonyManager.getUiccSlotsInfo()).thenReturn( twoSimSlotsDeviceActiveEsimActivePsim()); - int testSlot = UiccSlotUtil.getEsimSlotId(mContext); + int testSlot = UiccSlotUtil.getEsimSlotId(mContext,0); assertThat(testSlot).isEqualTo(0); } + @Test - public void getEsimSlotId_twoSimSlotsDeviceAndRemovableEsimIsSlot1_returnTheCorrectEsimSlot() { + public void getEsimSlotId_simIsRemovableEsimAndRemovableEsimIsSlot1_returnRemovableEsimSlot1() { + int subId = 0; + int cardId = 0; + mSubscriptionInfoList.add(createSubscriptionInfo(subId,-1, -1, true, cardId)); + mUiccCardInfo.add(createUiccCardInfo(true, 3, 0, false, -1, -1)); + mUiccCardInfo.add(createUiccCardInfo(true, cardId, 1, true, -1, -1)); + when(mTelephonyManager.getUiccSlotsInfo()).thenReturn( + twoSimSlotsDeviceActiveEsimActiveRemovableEsim()); + int testSlot = UiccSlotUtil.getEsimSlotId(mContext, subId); + + assertThat(testSlot).isEqualTo(1); + } + + @Test + public void getEsimSlotId_simIsRemovableEsimAndTwoRemovableSlots_returnRemovableEsimSlot1() { + int subId = 0; + int cardId = 0; + mSubscriptionInfoList.add(createSubscriptionInfo(subId,-1, -1, true, cardId)); + mUiccCardInfo.add(createUiccCardInfo(false, 4, 0, true, -1, -1)); + mUiccCardInfo.add(createUiccCardInfo(true, cardId, 1, true, -1, -1)); when(mTelephonyManager.getUiccSlotsInfo()).thenReturn( twoSimSlotsDeviceActivePsimActiveRemovableEsim()); - int testSlot = UiccSlotUtil.getEsimSlotId(mContext); + int testSlot = UiccSlotUtil.getEsimSlotId(mContext, subId); assertThat(testSlot).isEqualTo(1); } @@ -105,7 +135,7 @@ public class UiccSlotUtilTest { public void getEsimSlotId_twoSimSlotsDeviceAndEsimIsSlot1_returnTheCorrectEsimSlot() { when(mTelephonyManager.getUiccSlotsInfo()).thenReturn( twoSimSlotsDeviceActivePsimActiveEsim()); - int testSlot = UiccSlotUtil.getEsimSlotId(mContext); + int testSlot = UiccSlotUtil.getEsimSlotId(mContext,0); assertThat(testSlot).isEqualTo(1); } @@ -114,7 +144,7 @@ public class UiccSlotUtilTest { public void getEsimSlotId_noEimSlotDevice_returnTheCorrectEsimSlot() { when(mTelephonyManager.getUiccSlotsInfo()).thenReturn( oneSimSlotDeviceActivePsim()); - int testSlot = UiccSlotUtil.getEsimSlotId(mContext); + int testSlot = UiccSlotUtil.getEsimSlotId(mContext,0); assertThat(testSlot).isEqualTo(-1); } @@ -620,13 +650,38 @@ public class UiccSlotUtilTest { } private SubscriptionInfo createSubscriptionInfo(int logicalSlotIndex, int portIndex) { + return createSubscriptionInfo(0, logicalSlotIndex, portIndex, true, 25); + } + + private SubscriptionInfo createSubscriptionInfo(int subId, int logicalSlotIndex, int portIndex, + boolean isEmbedded, int cardId) { return new SubscriptionInfo( - 0, "", logicalSlotIndex, "", "", 0, 0, "", 0, null, "", "", "", - true /* isEmbedded */, - null, "", 25, + subId, "", + logicalSlotIndex, "", "", 0, 0, "", 0, null, "", "", "", + isEmbedded /* isEmbedded */, + null, "", + cardId, false, null, false, 0, 0, 0, null, null, true, portIndex); } + private UiccCardInfo createUiccCardInfo(boolean isEuicc, int cardId, int physicalSlotIndex, + boolean isRemovable, int logicalSlotIndex, int portIndex) { + return new UiccCardInfo( + isEuicc /* isEuicc */, + cardId /* cardId */, + null /* eid */, + physicalSlotIndex /* physicalSlotIndex */, + isRemovable /* isRemovable */, + false /* isMultipleEnabledProfileSupported */, + Collections.singletonList( + new UiccPortInfo( + "123451234567890" /* iccId */, + portIndex /* portIdx */, + logicalSlotIndex /* logicalSlotIdx */, + true /* isActive */) + )); + } + private List createActiveSubscriptionInfoListOneSim(int logicalSlotIndex, int portIndex) { List subscriptionInfoList = new ArrayList<>(); @@ -737,6 +792,12 @@ public class UiccSlotUtilTest { createUiccSlotInfo(true, false, 1, true)}; } + private UiccSlotInfo[] twoSimSlotsDeviceActiveEsimActiveRemovableEsim() { + return new UiccSlotInfo[]{ + createUiccSlotInfo(true, false, 0, true), + createUiccSlotInfo(true, true, 1, true)}; + } + private UiccSlotInfo[] twoSimSlotsDeviceActivePsimActiveRemovableEsim() { return new UiccSlotInfo[]{ createUiccSlotInfo(false, true, 0, true),