From f535e87e5114a585f2d9cc3ab1fe538677cd91ff Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Thu, 2 Apr 2020 16:29:36 +0100 Subject: [PATCH 1/9] Improve work profile unification flow When unifying work profile challenge, keep the device lock as long as it will still meet password requirement after unification. If not, prompt the user to set a new device lock and only unify work challenge after a compliant device lock is set. Bug: 148630506 Fix: 149682344 Test: make RunSettingsRoboTests ROBOTEST_FILTER='ChooseLockGenericTest|ChooseLockPasswordTest|ChooseLockPatternTest|LockUnificationPreferenceControllerTest' Change-Id: I99cde2650902927f6a4cc7c0cc7c6016e0dc283f --- .../settings/password/ChooseLockGeneric.java | 90 ++++++++++++------ .../settings/password/ChooseLockPassword.java | 40 +++++++- .../settings/password/ChooseLockPattern.java | 33 ++++++- .../password/ChooseLockSettingsHelper.java | 12 +++ .../password/SaveChosenLockWorkerBase.java | 19 ++++ .../LockUnificationPreferenceController.java | 95 +++++++------------ .../settings/security/SecuritySettings.java | 1 - .../password/ChooseLockGenericTest.java | 52 ++++++++++ .../password/ChooseLockPasswordTest.java | 15 +++ .../password/ChooseLockPatternTest.java | 15 +++ 10 files changed, 279 insertions(+), 93 deletions(-) diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java index 755d1586b8a..f50ea5f3a5f 100644 --- a/src/com/android/settings/password/ChooseLockGeneric.java +++ b/src/com/android/settings/password/ChooseLockGeneric.java @@ -143,7 +143,7 @@ public class ChooseLockGeneric extends SettingsActivity { static final int SKIP_FINGERPRINT_REQUEST = 104; private ChooseLockSettingsHelper mChooseLockSettingsHelper; - private DevicePolicyManager mDPM; + private DevicePolicyManager mDpm; private boolean mHasChallenge = false; private long mChallenge; private boolean mPasswordConfirmed = false; @@ -158,6 +158,8 @@ public class ChooseLockGeneric extends SettingsActivity { private boolean mIsSetNewPassword = false; private UserManager mUserManager; private ChooseLockGenericController mController; + private int mUnificationProfileId = UserHandle.USER_NULL; + private LockscreenCredential mUnificationProfileCredential; /** * From intent extra {@link ChooseLockSettingsHelper#EXTRA_KEY_REQUESTED_MIN_COMPLEXITY}. @@ -185,48 +187,57 @@ public class ChooseLockGeneric extends SettingsActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final Activity activity = getActivity(); + final Bundle arguments = getArguments(); if (!WizardManagerHelper.isDeviceProvisioned(activity) && !canRunBeforeDeviceProvisioned()) { Log.i(TAG, "Refusing to start because device is not provisioned"); activity.finish(); return; } - - String chooseLockAction = getActivity().getIntent().getAction(); - mFingerprintManager = Utils.getFingerprintManagerOrNull(getActivity()); - mFaceManager = Utils.getFaceManagerOrNull(getActivity()); - mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); - mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity()); - mLockPatternUtils = new LockPatternUtils(getActivity()); + final Intent intent = activity.getIntent(); + String chooseLockAction = intent.getAction(); + mFingerprintManager = Utils.getFingerprintManagerOrNull(activity); + mFaceManager = Utils.getFaceManagerOrNull(activity); + mDpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); + mChooseLockSettingsHelper = new ChooseLockSettingsHelper(activity); + mLockPatternUtils = new LockPatternUtils(activity); mIsSetNewPassword = ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(chooseLockAction) || ACTION_SET_NEW_PASSWORD.equals(chooseLockAction); // Defaults to needing to confirm credentials - final boolean confirmCredentials = getActivity().getIntent() + final boolean confirmCredentials = intent .getBooleanExtra(CONFIRM_CREDENTIALS, true); - if (getActivity() instanceof ChooseLockGeneric.InternalActivity) { + if (activity instanceof ChooseLockGeneric.InternalActivity) { mPasswordConfirmed = !confirmCredentials; - mUserPassword = getActivity().getIntent().getParcelableExtra( + mUserPassword = intent.getParcelableExtra( ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); } - mHasChallenge = getActivity().getIntent().getBooleanExtra( + mHasChallenge = intent.getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); - mChallenge = getActivity().getIntent().getLongExtra( + mChallenge = intent.getLongExtra( ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0); - mForFingerprint = getActivity().getIntent().getBooleanExtra( + mForFingerprint = intent.getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false); - mForFace = getActivity().getIntent().getBooleanExtra( + mForFace = intent.getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false); - mRequestedMinComplexity = getActivity().getIntent() + mRequestedMinComplexity = intent .getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE); mCallerAppName = - getActivity().getIntent().getStringExtra(EXTRA_KEY_CALLER_APP_NAME); - mIsCallingAppAdmin = getActivity().getIntent() + intent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME); + mIsCallingAppAdmin = intent .getBooleanExtra(EXTRA_KEY_IS_CALLING_APP_ADMIN, /* defValue= */ false); - mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean( + mForChangeCredRequiredForBoot = arguments != null && arguments.getBoolean( ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT); - mUserManager = UserManager.get(getActivity()); + mUserManager = UserManager.get(activity); + + if (arguments != null) { + mUnificationProfileCredential = (LockscreenCredential) arguments.getParcelable( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL); + mUnificationProfileId = arguments.getInt( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, + UserHandle.USER_NULL); + } if (savedInstanceState != null) { mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED); @@ -242,19 +253,19 @@ public class ChooseLockGeneric extends SettingsActivity { // from Settings app itself. // c) Otherwise, use UserHandle.myUserId(). mUserId = Utils.getSecureTargetUser( - getActivity().getActivityToken(), - UserManager.get(getActivity()), - getArguments(), - getActivity().getIntent().getExtras()).getIdentifier(); + activity.getActivityToken(), + UserManager.get(activity), + arguments, + intent.getExtras()).getIdentifier(); mController = new ChooseLockGenericController( getContext(), mUserId, mRequestedMinComplexity, mLockPatternUtils); if (ACTION_SET_NEW_PASSWORD.equals(chooseLockAction) - && UserManager.get(getActivity()).isManagedProfile(mUserId) + && UserManager.get(activity).isManagedProfile(mUserId) && mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) { - getActivity().setTitle(R.string.lock_settings_picker_title_profile); + activity.setTitle(R.string.lock_settings_picker_title_profile); } - mManagedPasswordProvider = ManagedLockPasswordProvider.get(getActivity(), mUserId); + mManagedPasswordProvider = ManagedLockPasswordProvider.get(activity, mUserId); if (mPasswordConfirmed) { updatePreferencesOrFinish(savedInstanceState != null); @@ -264,9 +275,9 @@ public class ChooseLockGeneric extends SettingsActivity { } } else if (!mWaitingForConfirmation) { ChooseLockSettingsHelper helper = - new ChooseLockSettingsHelper(this.getActivity(), this); + new ChooseLockSettingsHelper(activity, this); boolean managedProfileWithUnifiedLock = - UserManager.get(getActivity()).isManagedProfile(mUserId) + UserManager.get(activity).isManagedProfile(mUserId) && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId); boolean skipConfirmation = managedProfileWithUnifiedLock && !mIsSetNewPassword; if (skipConfirmation @@ -631,9 +642,22 @@ public class ChooseLockGeneric extends SettingsActivity { boolean hideDisabled) { final PreferenceScreen entries = getPreferenceScreen(); - int adminEnforcedQuality = mDPM.getPasswordQuality(null, mUserId); + int adminEnforcedQuality = mDpm.getPasswordQuality(null, mUserId); EnforcedAdmin enforcedAdmin = RestrictedLockUtilsInternal.checkIfPasswordQualityIsSet( getActivity(), mUserId); + // If we are to unify a work challenge at the end of the credential enrollment, manually + // merge any password policy from that profile here, so we are enrolling a compliant + // password. This is because once unified, the profile's password policy will + // be enforced on the new credential. + if (mUnificationProfileId != UserHandle.USER_NULL) { + int profileEnforceQuality = mDpm.getPasswordQuality(null, mUnificationProfileId); + if (profileEnforceQuality > adminEnforcedQuality) { + adminEnforcedQuality = profileEnforceQuality; + enforcedAdmin = EnforcedAdmin.combine(enforcedAdmin, + RestrictedLockUtilsInternal.checkIfPasswordQualityIsSet( + getActivity(), mUnificationProfileId)); + } + } for (ScreenLockType lock : ScreenLockType.values()) { String key = lock.preferenceKey; @@ -703,6 +727,9 @@ public class ChooseLockGeneric extends SettingsActivity { if (mUserPassword != null) { builder.setPassword(mUserPassword); } + if (mUnificationProfileId != UserHandle.USER_NULL) { + builder.setProfileToUnify(mUnificationProfileId, mUnificationProfileCredential); + } return builder.build(); } @@ -718,6 +745,9 @@ public class ChooseLockGeneric extends SettingsActivity { if (mUserPassword != null) { builder.setPattern(mUserPassword); } + if (mUnificationProfileId != UserHandle.USER_NULL) { + builder.setProfileToUnify(mUnificationProfileId, mUnificationProfileCredential); + } return builder.build(); } diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index ff94d8b8956..ebfc1afb436 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -32,6 +32,8 @@ import static com.android.internal.widget.PasswordValidationError.RECENTLY_USED; import static com.android.internal.widget.PasswordValidationError.TOO_LONG; import static com.android.internal.widget.PasswordValidationError.TOO_SHORT; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY; +import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL; +import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID; import android.app.Activity; import android.app.admin.DevicePolicyManager; @@ -46,6 +48,7 @@ import android.graphics.Typeface; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.os.UserHandle; import android.text.Editable; import android.text.InputType; import android.text.Selection; @@ -153,6 +156,18 @@ public class ChooseLockPassword extends SettingsActivity { return this; } + /** + * Configures the launch such that at the end of the password enrollment, one of its + * managed profile (specified by {@code profileId}) will have its lockscreen unified + * to the parent user. The profile's current lockscreen credential needs to be specified by + * {@code credential}. + */ + public IntentBuilder setProfileToUnify(int profileId, LockscreenCredential credential) { + mIntent.putExtra(EXTRA_KEY_UNIFICATION_PROFILE_ID, profileId); + mIntent.putExtra(EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL, credential); + return this; + } + public Intent build() { return mIntent; } @@ -208,6 +223,7 @@ public class ChooseLockPassword extends SettingsActivity { @PasswordComplexity private int mMinComplexity = PASSWORD_COMPLEXITY_NONE; protected int mUserId; private byte[] mPasswordHistoryHashFactor; + private int mUnificationProfileId = UserHandle.USER_NULL; private LockPatternUtils mLockPatternUtils; private SaveAndFinishWorker mSaveAndFinishWorker; @@ -367,8 +383,19 @@ public class ChooseLockPassword extends SettingsActivity { mRequestedQuality = intent.getIntExtra( LockPatternUtils.PASSWORD_TYPE_KEY, PASSWORD_QUALITY_NUMERIC); + mUnificationProfileId = intent.getIntExtra( + EXTRA_KEY_UNIFICATION_PROFILE_ID, UserHandle.USER_NULL); mMinMetrics = mLockPatternUtils.getRequestedPasswordMetrics(mUserId); + // If we are to unify a work challenge at the end of the credential enrollment, manually + // merge any password policy from that profile here, so we are enrolling a compliant + // password. This is because once unified, the profile's password policy will + // be enforced on the new credential. + if (mUnificationProfileId != UserHandle.USER_NULL) { + mMinMetrics.maxWith( + mLockPatternUtils.getRequestedPasswordMetrics(mUnificationProfileId)); + } + mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity()); if (intent.getBooleanExtra( @@ -833,8 +860,16 @@ public class ChooseLockPassword extends SettingsActivity { FRAGMENT_TAG_SAVE_AND_FINISH).commit(); getFragmentManager().executePendingTransactions(); - final boolean required = getActivity().getIntent().getBooleanExtra( + final Intent intent = getActivity().getIntent(); + final boolean required = intent.getBooleanExtra( EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true); + if (mUnificationProfileId != UserHandle.USER_NULL) { + try (LockscreenCredential profileCredential = (LockscreenCredential) + intent.getParcelableExtra(EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)) { + mSaveAndFinishWorker.setProfileToUnify(mUnificationProfileId, + profileCredential); + } + } mSaveAndFinishWorker.start(mLockPatternUtils, required, mHasChallenge, mChallenge, mChosenPassword, mCurrentCredential, mUserId); } @@ -912,6 +947,9 @@ public class ChooseLockPassword extends SettingsActivity { protected Pair saveAndVerifyInBackground() { final boolean success = mUtils.setLockCredential( mChosenPassword, mCurrentCredential, mUserId); + if (success) { + unifyProfileCredentialIfRequested(); + } Intent result = null; if (success && mHasChallenge) { byte[] token; diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java index b5670cacc43..ece3da8f247 100644 --- a/src/com/android/settings/password/ChooseLockPattern.java +++ b/src/com/android/settings/password/ChooseLockPattern.java @@ -16,6 +16,9 @@ package com.android.settings.password; +import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL; +import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID; + import android.app.Activity; import android.app.settings.SettingsEnums; import android.content.Context; @@ -23,6 +26,7 @@ import android.content.Intent; import android.content.res.ColorStateList; import android.content.res.Resources.Theme; import android.os.Bundle; +import android.os.UserHandle; import android.util.Log; import android.util.Pair; import android.util.TypedValue; @@ -50,6 +54,7 @@ import com.android.settings.SetupWizardUtils; import com.android.settings.Utils; import com.android.settings.core.InstrumentedFragment; import com.android.settings.notification.RedactionInterstitial; +import com.android.settings.password.ChooseLockPassword.IntentBuilder; import com.google.android.collect.Lists; import com.google.android.setupcompat.template.FooterBarMixin; @@ -130,6 +135,19 @@ public class ChooseLockPattern extends SettingsActivity { return this; } + /** + * Configures the launch such that at the end of the pattern enrollment, one of its + * managed profile (specified by {@code profileId}) will have its lockscreen unified + * to the parent user. The profile's current lockscreen credential needs to be specified by + * {@code credential}. + */ + public IntentBuilder setProfileToUnify(int profileId, LockscreenCredential credential) { + mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, profileId); + mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL, + credential); + return this; + } + public Intent build() { return mIntent; } @@ -810,8 +828,18 @@ public class ChooseLockPattern extends SettingsActivity { FRAGMENT_TAG_SAVE_AND_FINISH).commit(); getFragmentManager().executePendingTransactions(); - final boolean required = getActivity().getIntent().getBooleanExtra( + final Intent intent = getActivity().getIntent(); + final boolean required = intent.getBooleanExtra( EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true); + if (intent.hasExtra(EXTRA_KEY_UNIFICATION_PROFILE_ID)) { + try (LockscreenCredential profileCredential = (LockscreenCredential) + intent.getParcelableExtra(EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)) { + mSaveAndFinishWorker.setProfileToUnify( + intent.getIntExtra(EXTRA_KEY_UNIFICATION_PROFILE_ID, + UserHandle.USER_NULL), + profileCredential); + } + } mSaveAndFinishWorker.start(mChooseLockSettingsHelper.utils(), required, mHasChallenge, mChallenge, mChosenPattern, mCurrentCredential, mUserId); } @@ -863,6 +891,9 @@ public class ChooseLockPattern extends SettingsActivity { final int userId = mUserId; final boolean success = mUtils.setLockCredential(mChosenPattern, mCurrentCredential, userId); + if (success) { + unifyProfileCredentialIfRequested(); + } Intent result = null; if (success && mHasChallenge) { byte[] token; diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java index 3353d62053f..3989ee66f02 100644 --- a/src/com/android/settings/password/ChooseLockSettingsHelper.java +++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java @@ -33,6 +33,7 @@ import androidx.fragment.app.Fragment; import com.android.internal.widget.LockPatternUtils; import com.android.settings.SetupWizardUtils; import com.android.settings.Utils; +import com.android.settings.core.SubSettingLauncher; import com.google.android.setupcompat.util.WizardManagerHelper; @@ -49,6 +50,17 @@ public final class ChooseLockSettingsHelper { public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot"; public static final String EXTRA_KEY_FOREGROUND_ONLY = "foreground_only"; + /** + * When EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL and EXTRA_KEY_UNIFICATION_PROFILE_ID are + * provided to ChooseLockGeneric as fragment arguments {@link SubSettingLauncher#setArguments}, + * at the end of the password change flow, the supplied profile user + * (EXTRA_KEY_UNIFICATION_PROFILE_ID) will be unified to its parent. The current profile + * password is supplied by EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL. + */ + public static final String EXTRA_KEY_UNIFICATION_PROFILE_ID = "unification_profile_id"; + public static final String EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL = + "unification_profile_credential"; + /** * Intent extra for passing the requested min password complexity to later steps in the set new * screen lock flow. diff --git a/src/com/android/settings/password/SaveChosenLockWorkerBase.java b/src/com/android/settings/password/SaveChosenLockWorkerBase.java index 2798b3d7f47..26e4d5aa8ad 100644 --- a/src/com/android/settings/password/SaveChosenLockWorkerBase.java +++ b/src/com/android/settings/password/SaveChosenLockWorkerBase.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; +import android.os.UserHandle; import android.os.UserManager; import android.util.Pair; import android.widget.Toast; @@ -27,6 +28,7 @@ import android.widget.Toast; import androidx.fragment.app.Fragment; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockscreenCredential; import com.android.settings.R; /** @@ -44,6 +46,8 @@ abstract class SaveChosenLockWorkerBase extends Fragment { protected long mChallenge; protected boolean mWasSecureBefore; protected int mUserId; + protected int mUnificationProfileId = UserHandle.USER_NULL; + protected LockscreenCredential mUnificationProfileCredential; private boolean mBlocking; @@ -106,12 +110,27 @@ abstract class SaveChosenLockWorkerBase extends Fragment { if (mListener != null) { mListener.onChosenLockSaveFinished(mWasSecureBefore, mResultData); } + if (mUnificationProfileCredential != null) { + mUnificationProfileCredential.zeroize(); + } } public void setBlocking(boolean blocking) { mBlocking = blocking; } + public void setProfileToUnify(int profileId, LockscreenCredential credential) { + mUnificationProfileId = profileId; + mUnificationProfileCredential = credential.duplicate(); + } + + protected void unifyProfileCredentialIfRequested() { + if (mUnificationProfileId != UserHandle.USER_NULL) { + mUtils.setSeparateProfileChallengeEnabled(mUnificationProfileId, false, + mUnificationProfileCredential); + } + } + private class Task extends AsyncTask> { @Override diff --git a/src/com/android/settings/security/LockUnificationPreferenceController.java b/src/com/android/settings/security/LockUnificationPreferenceController.java index 4bac601cf26..9cacf8e2eca 100644 --- a/src/com/android/settings/security/LockUnificationPreferenceController.java +++ b/src/com/android/settings/security/LockUnificationPreferenceController.java @@ -16,7 +16,6 @@ package com.android.settings.security; -import static com.android.settings.security.SecuritySettings.UNIFY_LOCK_CONFIRM_DEVICE_REQUEST; import static com.android.settings.security.SecuritySettings.UNIFY_LOCK_CONFIRM_PROFILE_REQUEST; import static com.android.settings.security.SecuritySettings.UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST; @@ -48,12 +47,14 @@ import com.android.settingslib.core.AbstractPreferenceController; * Controller for password unification/un-unification flows. * * When password is being unified, there may be two cases: - * 1. If work password is not empty and satisfies device-wide policies (if any), it will be made - * into device-wide password. To do that we need both current device and profile passwords - * because both of them will be changed as a result. - * 2. Otherwise device-wide password is preserved. In this case we only need current profile - * password, but after unifying the passwords we proceed to ask the user for a new device - * password. + * 1. If device password will satisfy device-wide policies post-unification (when password policy + * set on the work challenge will be enforced on device password), the device password is + * preserved while work challenge is unified. Only the current work challenge is required + * in this flow. + * 2. Otherwise the user will need to enroll a new compliant device password before unification + * takes place. In this case we first confirm the current work challenge, then guide the user + * through an enrollment flow for the new device password, and finally unify the work challenge + * at the very end. */ public class LockUnificationPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener { @@ -73,7 +74,7 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr private LockscreenCredential mCurrentDevicePassword; private LockscreenCredential mCurrentProfilePassword; - private boolean mKeepDeviceLock; + private boolean mRequireNewDevicePassword; @Override public void displayPreference(PreferenceScreen screen) { @@ -112,13 +113,9 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr } final boolean useOneLock = (Boolean) value; if (useOneLock) { - // Keep current device (personal) lock if the profile lock is empty or is not compliant - // with the policy on personal side. - mKeepDeviceLock = - mLockPatternUtils.getKeyguardStoredPasswordQuality(mProfileUserId) - < DevicePolicyManager.PASSWORD_QUALITY_SOMETHING - || !mDpm.isProfileActivePasswordSufficientForParent(mProfileUserId); - UnificationConfirmationDialog.newInstance(!mKeepDeviceLock).show(mHost); + mRequireNewDevicePassword = !mDpm.isPasswordSufficientAfterProfileUnification( + UserHandle.myUserId(), mProfileUserId); + startUnification(); } else { final String title = mContext.getString(R.string.unlock_set_unlock_launch_picker_title); final ChooseLockSettingsHelper helper = @@ -149,13 +146,9 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr public boolean handleActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST && resultCode == Activity.RESULT_OK) { - ununifyLocks(); - return true; - } else if (requestCode == UNIFY_LOCK_CONFIRM_DEVICE_REQUEST - && resultCode == Activity.RESULT_OK) { mCurrentDevicePassword = data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); - launchConfirmProfileLock(); + ununifyLocks(); return true; } else if (requestCode == UNIFY_LOCK_CONFIRM_PROFILE_REQUEST && resultCode == Activity.RESULT_OK) { @@ -170,67 +163,44 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr private void ununifyLocks() { final Bundle extras = new Bundle(); extras.putInt(Intent.EXTRA_USER_ID, mProfileUserId); + extras.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mCurrentDevicePassword); new SubSettingLauncher(mContext) .setDestination(ChooseLockGeneric.ChooseLockGenericFragment.class.getName()) - .setTitleRes(R.string.lock_settings_picker_title_profile) + .setTitleRes(R.string.lock_settings_picker_title_profile) .setSourceMetricsCategory(mHost.getMetricsCategory()) .setArguments(extras) .launch(); } - /** Asks the user to confirm device lock (if there is one) and proceeds to ask profile lock. */ - private void launchConfirmDeviceAndProfileLock() { - final String title = mContext.getString( - R.string.unlock_set_unlock_launch_picker_title); - final ChooseLockSettingsHelper helper = - new ChooseLockSettingsHelper(mHost.getActivity(), mHost); - if (!helper.launchConfirmationActivity( - UNIFY_LOCK_CONFIRM_DEVICE_REQUEST, title, true, MY_USER_ID)) { - launchConfirmProfileLock(); - } - } - - private void launchConfirmProfileLock() { + void startUnification() { + // Confirm profile lock final String title = mContext.getString( R.string.unlock_set_unlock_launch_picker_title_profile); final ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(mHost.getActivity(), mHost); if (!helper.launchConfirmationActivity( UNIFY_LOCK_CONFIRM_PROFILE_REQUEST, title, true, mProfileUserId)) { + // If profile has no lock, go straight to unification. unifyLocks(); // TODO: update relevant prefs. // createPreferenceHierarchy(); } } - void startUnification() { - // If the device lock stays the same, only confirm profile lock. Otherwise confirm both. - if (mKeepDeviceLock) { - launchConfirmProfileLock(); - } else { - launchConfirmDeviceAndProfileLock(); - } - } - private void unifyLocks() { - if (mKeepDeviceLock) { - unifyKeepingDeviceLock(); - promptForNewDeviceLock(); + if (mRequireNewDevicePassword) { + promptForNewDeviceLockAndThenUnify(); } else { - unifyKeepingWorkLock(); + unifyKeepingDeviceLock(); + } + if (mCurrentDevicePassword != null) { + mCurrentDevicePassword.zeroize(); + mCurrentDevicePassword = null; + } + if (mCurrentProfilePassword != null) { + mCurrentProfilePassword.zeroize(); + mCurrentProfilePassword = null; } - mCurrentDevicePassword = null; - mCurrentProfilePassword = null; - } - - private void unifyKeepingWorkLock() { - mLockPatternUtils.setLockCredential( - mCurrentProfilePassword, mCurrentDevicePassword, MY_USER_ID); - mLockPatternUtils.setSeparateProfileChallengeEnabled(mProfileUserId, false, - mCurrentProfilePassword); - final boolean profilePatternVisibility = - mLockPatternUtils.isVisiblePatternEnabled(mProfileUserId); - mLockPatternUtils.setVisiblePatternEnabled(profilePatternVisibility, MY_USER_ID); } private void unifyKeepingDeviceLock() { @@ -238,11 +208,16 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr mCurrentProfilePassword); } - private void promptForNewDeviceLock() { + private void promptForNewDeviceLockAndThenUnify() { + final Bundle extras = new Bundle(); + extras.putInt(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, mProfileUserId); + extras.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL, + mCurrentProfilePassword); new SubSettingLauncher(mContext) .setDestination(ChooseLockGeneric.ChooseLockGenericFragment.class.getName()) .setTitleRes(R.string.lock_settings_picker_title) .setSourceMetricsCategory(mHost.getMetricsCategory()) + .setArguments(extras) .launch(); } diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java index effbd70dc82..c8288c6c7f2 100644 --- a/src/com/android/settings/security/SecuritySettings.java +++ b/src/com/android/settings/security/SecuritySettings.java @@ -47,7 +47,6 @@ public class SecuritySettings extends DashboardFragment { private static final String WORK_PROFILE_SECURITY_CATEGORY = "security_category_profile"; public static final int CHANGE_TRUST_AGENT_SETTINGS = 126; - public static final int UNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 128; public static final int UNIFY_LOCK_CONFIRM_PROFILE_REQUEST = 129; public static final int UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 130; diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java index 8340243cf49..b535bc142d3 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java @@ -35,12 +35,14 @@ import static org.robolectric.Shadows.shadowOf; import android.app.Activity; import android.app.admin.DevicePolicyManager; import android.content.Intent; +import android.os.Bundle; import android.provider.Settings.Global; import androidx.annotation.Nullable; import androidx.preference.Preference; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockscreenCredential; import com.android.settings.R; import com.android.settings.biometrics.BiometricEnrollBase; import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment; @@ -312,6 +314,56 @@ public class ChooseLockGenericTest { .isEqualTo("app name"); } + @Test + public void testUnifyProfile_IntentPassedToChooseLockPassword() { + final Bundle arguments = new Bundle(); + arguments.putInt(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, 11); + arguments.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL, + LockscreenCredential.createNone()); + mFragment.setArguments(arguments); + + Intent intent = new Intent().putExtra( + LockPatternUtils.PASSWORD_TYPE_KEY, + DevicePolicyManager.PASSWORD_QUALITY_NUMERIC); + initActivity(intent); + + mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */); + + Intent nextIntent = shadowOf(mActivity).getNextStartedActivity(); + assertThat(nextIntent).isNotNull(); + assertThat(nextIntent.getComponent().getClassName()).isEqualTo( + ChooseLockPassword.class.getName()); + assertThat(nextIntent.getIntExtra( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, 0)).isEqualTo(11); + assertThat((LockscreenCredential) nextIntent.getParcelableExtra( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)).isNotNull(); + } + + @Test + public void testUnifyProfile_IntentPassedToChooseLockPattern() { + final Bundle arguments = new Bundle(); + arguments.putInt(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, 13); + arguments.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL, + LockscreenCredential.createNone()); + mFragment.setArguments(arguments); + + Intent intent = new Intent().putExtra( + LockPatternUtils.PASSWORD_TYPE_KEY, + DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); + initActivity(intent); + + mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */); + + Intent nextIntent = shadowOf(mActivity).getNextStartedActivity(); + assertThat(nextIntent).isNotNull(); + assertThat(nextIntent.getComponent().getClassName()).isEqualTo( + ChooseLockPattern.class.getName()); + assertThat(nextIntent.getIntExtra( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, 0)).isEqualTo(13); + assertThat((LockscreenCredential) nextIntent.getParcelableExtra( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)).isNotNull(); + } + private void initActivity(@Nullable Intent intent) { if (intent == null) { intent = new Intent(); diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java index 4bbf51d981f..5ec6f41abbf 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java @@ -147,6 +147,21 @@ public class ChooseLockPasswordTest { assertThat(intent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isFalse(); } + @Test + public void intentBuilder_setProfileToUnify_shouldAddExtras() { + Intent intent = new IntentBuilder(application) + .setProfileToUnify(23, LockscreenCredential.createNone()) + .build(); + + assertThat(intent.getIntExtra(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, 0)) + .named("EXTRA_KEY_UNIFICATION_PROFILE_ID") + .isEqualTo(23); + assertThat((LockscreenCredential) intent.getParcelableExtra( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)) + .named("EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL") + .isNotNull(); + } + @Test public void processAndValidatePasswordRequirements_noMinPasswordComplexity() { mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_ALPHABETIC); diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java index 01007449fd6..557e7c169c6 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java @@ -92,6 +92,21 @@ public class ChooseLockPatternTest { .isEqualTo(123); } + @Test + public void intentBuilder_setProfileToUnify_shouldAddExtras() { + Intent intent = new IntentBuilder(application) + .setProfileToUnify(23, LockscreenCredential.createNone()) + .build(); + + assertThat(intent.getIntExtra(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, 0)) + .named("EXTRA_KEY_UNIFICATION_PROFILE_ID") + .isEqualTo(23); + assertThat((LockscreenCredential) intent.getParcelableExtra( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)) + .named("EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL") + .isNotNull(); + } + @Config(qualifiers = "sw400dp") @Test public void fingerprintExtraSet_shouldDisplayFingerprintIcon() { From 7d6c329746e945369677ed6b894acadbdb46eb79 Mon Sep 17 00:00:00 2001 From: Vince Leung Date: Tue, 10 Mar 2020 14:00:02 -0700 Subject: [PATCH 2/9] Use super method for Vibration preferences onDisplayPreferenceDialog is overriden to handle BT related preferences but VibrationPreferences require the super method of onDisplayPreferenceDialog. Therefore if VibrationPreferences wants to display a dialog, use the super method instead of the overriden method. Bug: 150661723 Change-Id: I3f8e86e1d1f32fa6eae2798d3bad3cb48402db7b Merged-In: I3f8e86e1d1f32fa6eae2798d3bad3cb48402db7b (cherry picked from commit eb27aefa325ac4b254d618d0005d0657bf86b2fc) --- src/com/android/settings/notification/SoundSettings.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java index 746a2df8ab2..6c2016bb940 100644 --- a/src/com/android/settings/notification/SoundSettings.java +++ b/src/com/android/settings/notification/SoundSettings.java @@ -76,6 +76,7 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult private RingtonePreference mRequestPreference; private UpdatableListPreferenceDialogFragment mDialogFragment; private String mHfpOutputControllerKey; + private String mVibrationPreferencesKey = "vibration_preference_screen"; @Override public int getMetricsCategory() { @@ -127,6 +128,10 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult @Override public void onDisplayPreferenceDialog(Preference preference) { + if (TextUtils.equals(mVibrationPreferencesKey, preference.getKey())) { + super.onDisplayPreferenceDialog(preference); + return; + } final int metricsCategory; if (mHfpOutputControllerKey.equals(preference.getKey())) { metricsCategory = SettingsEnums.DIALOG_SWITCH_HFP_DEVICES; @@ -311,4 +316,4 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult mDialogFragment.onListPreferenceUpdated(preference); } } -} \ No newline at end of file +} From 77c41c1a5ab0f9ea1a4f55f41ade1e3193bc6532 Mon Sep 17 00:00:00 2001 From: Daniel Chapin Date: Tue, 14 Apr 2020 15:47:48 +0000 Subject: [PATCH 3/9] Revert "Don't write user_switcher_enabled value when enter this Settings" This reverts commit 898d6b4d73f40b08a91f69dbdf3b67550f1df198. Reason for revert: Causing a regression Bug: 153944718 Change-Id: If96441618d32a65b0bae4c5c26fb3b278556cc8c --- .../android/settings/users/MultiUserSwitchBarController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/com/android/settings/users/MultiUserSwitchBarController.java b/src/com/android/settings/users/MultiUserSwitchBarController.java index 58de14963fa..a5fdf9b3279 100644 --- a/src/com/android/settings/users/MultiUserSwitchBarController.java +++ b/src/com/android/settings/users/MultiUserSwitchBarController.java @@ -52,6 +52,8 @@ public class MultiUserSwitchBarController implements SwitchWidgetController.OnSw mListener = listener; mUserCapabilities = UserCapabilities.create(context); mSwitchBar.setChecked(mUserCapabilities.mUserSwitcherEnabled); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.USER_SWITCHER_ENABLED, mSwitchBar.isChecked() ? 1 : 0); if (mUserCapabilities.mDisallowSwitchUser) { mSwitchBar.setDisabledByAdmin(RestrictedLockUtilsInternal From 1845421ef8fae20172f207347ad5709a2b23b631 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Mon, 13 Apr 2020 18:13:29 -0400 Subject: [PATCH 4/9] Update flows for notification history - Remove settings observer, since the switch is right here - Add 'notifications will soon appear' whenever history is empty Test: manual Fixes: 153677280 Fixes: 152578971 Change-Id: Ia372fafb3688fe7d45a7634e379f022bcffea169 --- res/layout/notification_history.xml | 24 +++- .../history/NotificationHistoryActivity.java | 122 ++++++++---------- 2 files changed, 72 insertions(+), 74 deletions(-) diff --git a/res/layout/notification_history.xml b/res/layout/notification_history.xml index f5fae3f606f..18bb58b646d 100644 --- a/res/layout/notification_history.xml +++ b/res/layout/notification_history.xml @@ -40,7 +40,6 @@ android:layout_width="67dp" android:layout_height="67dp" android:layout_gravity="center_horizontal" - android:contentDescription="@string/notification_history" android:scaleType="fitCenter" android:focusable="false" android:tint="?android:attr/colorControlNormal" @@ -50,7 +49,6 @@ android:id="@+id/history_off_title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_below="@+id/history_image" android:layout_marginTop="48dp" android:layout_marginStart="48dp" android:layout_marginEnd="48dp" @@ -63,7 +61,6 @@ android:id="@+id/history_off_summary" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_below="@+id/history_off_title" android:layout_marginStart="48dp" android:layout_marginEnd="48dp" android:layout_marginTop="16dp" @@ -73,17 +70,33 @@ android:textAppearance="?android:attr/textAppearanceSmall" android:text="@string/notification_history_off_summary" /> + + + + @@ -98,7 +111,6 @@ android:layout_gravity="center_horizontal" android:textAlignment="center" android:focusable="true" - android:visibility="gone" android:textAppearance="?android:attr/textAppearanceSmall" android:text="@string/history_toggled_on_summary" /> diff --git a/src/com/android/settings/notification/history/NotificationHistoryActivity.java b/src/com/android/settings/notification/history/NotificationHistoryActivity.java index 73befeb4801..144d102e651 100644 --- a/src/com/android/settings/notification/history/NotificationHistoryActivity.java +++ b/src/com/android/settings/notification/history/NotificationHistoryActivity.java @@ -22,15 +22,11 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.INotificationManager; import android.content.ComponentName; -import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; -import android.database.ContentObserver; -import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.UserHandle; import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; @@ -50,9 +46,13 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.settings.R; import com.android.settings.notification.NotificationBackend; import com.android.settings.widget.SwitchBar; +import com.android.settingslib.utils.ThreadUtils; import java.util.ArrayList; import java.util.Arrays; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; public class NotificationHistoryActivity extends Activity { @@ -60,18 +60,22 @@ public class NotificationHistoryActivity extends Activity { private ViewGroup mHistoryOn; private ViewGroup mHistoryOff; + private ViewGroup mHistoryEmpty; private ViewGroup mTodayView; private ViewGroup mSnoozeView; private ViewGroup mDismissView; + private SwitchBar mSwitchBar; - private SettingsObserver mSettingsObserver = new SettingsObserver(); private HistoryLoader mHistoryLoader; private INotificationManager mNm; private PackageManager mPm; + private CountDownLatch mCountdownLatch; + private Future mCountdownFuture; private HistoryLoader.OnHistoryLoaderListener mOnHistoryLoaderListener = notifications -> { findViewById(R.id.today_list).setVisibility( notifications.isEmpty() ? View.GONE : View.VISIBLE); + mCountdownLatch.countDown(); // for each package, new header and recycler view for (NotificationHistoryPackage nhp : notifications) { View viewForPackage = LayoutInflater.from(this) @@ -124,6 +128,8 @@ public class NotificationHistoryActivity extends Activity { mDismissView = findViewById(R.id.recently_dismissed_list); mHistoryOff = findViewById(R.id.history_off); mHistoryOn = findViewById(R.id.history_on); + mHistoryEmpty = findViewById(R.id.history_on_empty); + mSwitchBar = findViewById(R.id.switch_bar); } @Override @@ -131,6 +137,8 @@ public class NotificationHistoryActivity extends Activity { super.onResume(); mPm = getPackageManager(); + // wait for history loading and recent/snooze loading + mCountdownLatch = new CountDownLatch(2); mTodayView.removeAllViews(); mHistoryLoader = new HistoryLoader(this, new NotificationBackend(), mPm); @@ -144,9 +152,25 @@ public class NotificationHistoryActivity extends Activity { } catch (RemoteException e) { Log.e(TAG, "Cannot register listener", e); } - mSettingsObserver.observe(); bindSwitch(); + + mCountdownFuture = ThreadUtils.postOnBackgroundThread(() -> { + try { + mCountdownLatch.await(2, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Slog.e(TAG, "timed out waiting for loading", e); + } + ThreadUtils.postOnMainThread(() -> { + if (mSwitchBar.isChecked() + && findViewById(R.id.today_list).getVisibility() == View.GONE + && mSnoozeView.getVisibility() == View.GONE + && mDismissView.getVisibility() == View.GONE) { + mHistoryOn.setVisibility(View.GONE); + mHistoryEmpty.setVisibility(View.VISIBLE); + } + }); + }); } @Override @@ -156,24 +180,30 @@ public class NotificationHistoryActivity extends Activity { } catch (RemoteException e) { Log.e(TAG, "Cannot unregister listener", e); } - mSettingsObserver.stopObserving(); super.onPause(); } + @Override + public void onDestroy() { + if (mCountdownFuture != null) { + mCountdownFuture.cancel(true); + } + super.onDestroy(); + } + private void bindSwitch() { - SwitchBar bar = findViewById(R.id.switch_bar); - if (bar != null) { - bar.setSwitchBarText(R.string.notification_history_toggle, + if (mSwitchBar != null) { + mSwitchBar.setSwitchBarText(R.string.notification_history_toggle, R.string.notification_history_toggle); - bar.show(); + mSwitchBar.show(); try { - bar.addOnSwitchChangeListener(mOnSwitchClickListener); + mSwitchBar.addOnSwitchChangeListener(mOnSwitchClickListener); } catch (IllegalStateException e) { // an exception is thrown if you try to add the listener twice } - bar.setChecked(Settings.Secure.getInt(getContentResolver(), + mSwitchBar.setChecked(Settings.Secure.getInt(getContentResolver(), NOTIFICATION_HISTORY_ENABLED, 0) == 1); - toggleViews(bar.isChecked()); + toggleViews(mSwitchBar.isChecked()); } } @@ -184,53 +214,9 @@ public class NotificationHistoryActivity extends Activity { } else { mHistoryOn.setVisibility(View.GONE); mHistoryOff.setVisibility(View.VISIBLE); - mHistoryOff.findViewById(R.id.history_off_title).setVisibility(View.VISIBLE); - mHistoryOff.findViewById(R.id.history_off_summary).setVisibility(View.VISIBLE); - mHistoryOff.findViewById(R.id.history_toggled_on_title).setVisibility(View.GONE); - mHistoryOff.findViewById(R.id.history_toggled_on_summary).setVisibility(View.GONE); mTodayView.removeAllViews(); } - } - - private void onHistoryEnabledChanged(boolean enabled) { - if (enabled) { - mHistoryLoader.load(mOnHistoryLoaderListener); - } - } - - final class SettingsObserver extends ContentObserver { - private final Uri NOTIFICATION_HISTORY_URI - = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_HISTORY_ENABLED); - - SettingsObserver() { - super(null); - } - - void observe() { - ContentResolver resolver = getContentResolver(); - resolver.registerContentObserver(NOTIFICATION_HISTORY_URI, - false, this, UserHandle.USER_ALL); - } - - void stopObserving() { - ContentResolver resolver = getContentResolver(); - resolver.unregisterContentObserver(this); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - update(uri); - } - - public void update(Uri uri) { - ContentResolver resolver = getContentResolver(); - if (uri == null || NOTIFICATION_HISTORY_URI.equals(uri)) { - boolean historyEnabled = Settings.Secure.getInt(resolver, - Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0) - != 0; - onHistoryEnabledChanged(historyEnabled); - } - } + mHistoryEmpty.setVisibility(View.GONE); } private final SwitchBar.OnSwitchChangeListener mOnSwitchClickListener = @@ -239,16 +225,14 @@ public class NotificationHistoryActivity extends Activity { NOTIFICATION_HISTORY_ENABLED, isChecked ? 1 : 0); mHistoryOn.setVisibility(View.GONE); - mHistoryOff.findViewById(R.id.history_off_title).setVisibility( - isChecked ? View.GONE : View.VISIBLE); - mHistoryOff.findViewById(R.id.history_off_summary).setVisibility( - isChecked ? View.GONE : View.VISIBLE); - mHistoryOff.findViewById(R.id.history_toggled_on_title).setVisibility( - isChecked ? View.VISIBLE : View.GONE); - mHistoryOff.findViewById(R.id.history_toggled_on_summary).setVisibility( - isChecked ? View.VISIBLE : View.GONE); + if (isChecked) { + mHistoryEmpty.setVisibility(View.VISIBLE); + mHistoryOff.setVisibility(View.GONE); + } else { + mHistoryOff.setVisibility(View.VISIBLE); + mHistoryEmpty.setVisibility(View.GONE); + } mTodayView.removeAllViews(); - mHistoryOff.setVisibility(View.VISIBLE); }; private final NotificationListenerService mListener = new NotificationListenerService() { @@ -303,6 +287,8 @@ public class NotificationHistoryActivity extends Activity { ((NotificationSbnAdapter) mDismissedRv.getAdapter()).onRebuildComplete( new ArrayList<>(Arrays.asList(dismissed))); } + + mCountdownLatch.countDown(); } @Override From 2483124478271096127c788f1c64cc46ba385680 Mon Sep 17 00:00:00 2001 From: Yanting Yang Date: Wed, 15 Apr 2020 08:41:53 +0800 Subject: [PATCH 5/9] Fix breadcrumb for the search results of Custom restrictions page Settings Search need Settings to provide the custom site map pairs to build up the full breadcrumb for the search results of Custom restrictions page. Impact search results: Don't turn on screen Don't wake for notifications Hide notification dots on app icons Hide status bar icons at top of screen Don't pop notifications on screen Hide from pull-down shade Custom restrictions Bug: 147851992 Bug: 151206664 Test: visual and robotests Change-Id: I01e359eabcdc362e2a1fde5f3bc4ae5dc6918030 --- .../android/settings/search/CustomSiteMapRegistry.java | 4 ++++ .../settings/search/CustomSiteMapRegistryTest.java | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/src/com/android/settings/search/CustomSiteMapRegistry.java b/src/com/android/settings/search/CustomSiteMapRegistry.java index 756479b2495..afda72b2d68 100644 --- a/src/com/android/settings/search/CustomSiteMapRegistry.java +++ b/src/com/android/settings/search/CustomSiteMapRegistry.java @@ -27,6 +27,8 @@ import com.android.settings.fuelgauge.PowerUsageSummary; import com.android.settings.location.LocationSettings; import com.android.settings.location.RecentLocationRequestSeeAllFragment; import com.android.settings.network.NetworkDashboardFragment; +import com.android.settings.notification.zen.ZenModeBlockedEffectsSettings; +import com.android.settings.notification.zen.ZenModeRestrictNotificationsSettings; import com.android.settings.security.SecuritySettings; import com.android.settings.security.screenlock.ScreenLockSettings; import com.android.settings.system.SystemDashboardFragment; @@ -59,5 +61,7 @@ public class CustomSiteMapRegistry { ConnectedDeviceDashboardFragment.class.getName()); CUSTOM_SITE_MAP.put(UserBackupSettingsActivity.class.getName(), SystemDashboardFragment.class.getName()); + CUSTOM_SITE_MAP.put(ZenModeBlockedEffectsSettings.class.getName(), + ZenModeRestrictNotificationsSettings.class.getName()); } } diff --git a/tests/robotests/src/com/android/settings/search/CustomSiteMapRegistryTest.java b/tests/robotests/src/com/android/settings/search/CustomSiteMapRegistryTest.java index 5c78a6bde68..a3e88d96ca3 100644 --- a/tests/robotests/src/com/android/settings/search/CustomSiteMapRegistryTest.java +++ b/tests/robotests/src/com/android/settings/search/CustomSiteMapRegistryTest.java @@ -27,6 +27,8 @@ import com.android.settings.fuelgauge.PowerUsageSummary; import com.android.settings.location.LocationSettings; import com.android.settings.location.RecentLocationRequestSeeAllFragment; import com.android.settings.network.NetworkDashboardFragment; +import com.android.settings.notification.zen.ZenModeBlockedEffectsSettings; +import com.android.settings.notification.zen.ZenModeRestrictNotificationsSettings; import com.android.settings.security.SecuritySettings; import com.android.settings.security.screenlock.ScreenLockSettings; import com.android.settings.system.SystemDashboardFragment; @@ -85,4 +87,11 @@ public class CustomSiteMapRegistryTest { UserBackupSettingsActivity.class.getName())).isEqualTo( SystemDashboardFragment.class.getName()); } + + @Test + public void shouldContainZenModeBlockedEffectsSettingsPairs() { + assertThat(CustomSiteMapRegistry.CUSTOM_SITE_MAP.get( + ZenModeBlockedEffectsSettings.class.getName())).isEqualTo( + ZenModeRestrictNotificationsSettings.class.getName()); + } } From 44b74c9cfee9a6d35355a48018ec306705c21130 Mon Sep 17 00:00:00 2001 From: Sunny Shao Date: Wed, 4 Mar 2020 12:34:15 +0800 Subject: [PATCH 6/9] Refactor the OpenSupportedLinks - Use the AppInfoWithHeader to replace the DashboardFragment. - It provide the AppHeader controller and handle the app update/remove event. Fixes: 147996227 Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.applications.OpenSupportedLinksTest Change-Id: I1633c39fc926805a379c5c31845897914e5181a6 --- res/xml/open_supported_links.xml | 14 +- .../AppHeaderPreferenceController.java | 106 ---------- .../applications/AppLaunchSettings.java | 7 +- ...penSupportedLinksPreferenceController.java | 184 ----------------- .../applications/OpenSupportedLinks.java | 194 ++++++++++++++---- ...upportedLinksPreferenceControllerTest.java | 131 ------------ .../applications/OpenSupportedLinksTest.java | 94 ++++++++- 7 files changed, 247 insertions(+), 483 deletions(-) delete mode 100644 src/com/android/settings/applications/AppHeaderPreferenceController.java delete mode 100644 src/com/android/settings/applications/AppOpenSupportedLinksPreferenceController.java delete mode 100644 tests/robotests/src/com/android/settings/applications/AppOpenSupportedLinksPreferenceControllerTest.java diff --git a/res/xml/open_supported_links.xml b/res/xml/open_supported_links.xml index 0f6e2ca8a16..1ffec1b8045 100644 --- a/res/xml/open_supported_links.xml +++ b/res/xml/open_supported_links.xml @@ -18,17 +18,9 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/app_launch_open_domain_urls_title"> - - + android:key="supported_links_radio_group" + android:title="@string/app_link_open_always"> - \ No newline at end of file + diff --git a/src/com/android/settings/applications/AppHeaderPreferenceController.java b/src/com/android/settings/applications/AppHeaderPreferenceController.java deleted file mode 100644 index 0f473e7f08c..00000000000 --- a/src/com/android/settings/applications/AppHeaderPreferenceController.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2020 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.applications; - -import static com.android.settings.widget.EntityHeaderController.ActionType; - -import android.app.Activity; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; - -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settings.Utils; -import com.android.settings.core.BasePreferenceController; -import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.widget.EntityHeaderController; -import com.android.settingslib.applications.AppUtils; -import com.android.settingslib.core.lifecycle.Lifecycle; -import com.android.settingslib.core.lifecycle.LifecycleObserver; -import com.android.settingslib.core.lifecycle.events.OnResume; -import com.android.settingslib.widget.LayoutPreference; - -/** - * The header controller displays on the top of the page. - */ -public class AppHeaderPreferenceController extends BasePreferenceController implements - LifecycleObserver, OnResume { - private DashboardFragment mParent; - private PackageInfo mPackageInfo; - private Lifecycle mLifecycle; - private LayoutPreference mHeaderPreference; - - public AppHeaderPreferenceController(Context context, String preferenceKey) { - super(context, preferenceKey); - } - - /** - * @param fragment set the parent fragment. - * @return return controller-self. - */ - public AppHeaderPreferenceController setParentFragment(DashboardFragment fragment) { - mParent = fragment; - return this; - } - - /** - * @param packageInfo set the {@link PackageInfo}. - * @return return controller-self. - */ - public AppHeaderPreferenceController setPackageInfo(PackageInfo packageInfo) { - mPackageInfo = packageInfo; - return this; - } - - /** - * @param lifeCycle set the {@link Lifecycle}. - * @return return controller-self. - */ - public AppHeaderPreferenceController setLifeCycle(Lifecycle lifeCycle) { - mLifecycle = lifeCycle; - return this; - } - - @Override - public void displayPreference(PreferenceScreen screen) { - super.displayPreference(screen); - mHeaderPreference = screen.findPreference(getPreferenceKey()); - } - - @Override - public int getAvailabilityStatus() { - return AVAILABLE; - } - - @Override - public void onResume() { - final Activity activity = mParent.getActivity(); - final PackageManager packageManager = activity.getPackageManager(); - EntityHeaderController - .newInstance(activity, mParent, mHeaderPreference.findViewById(R.id.entity_header)) - .setRecyclerView(mParent.getListView(), mLifecycle) - .setIcon(Utils.getBadgedIcon(mParent.getContext(), mPackageInfo.applicationInfo)) - .setLabel(mPackageInfo.applicationInfo.loadLabel(packageManager)) - .setSummary(mPackageInfo) - .setIsInstantApp(AppUtils.isInstant(mPackageInfo.applicationInfo)) - .setPackageName(mPackageInfo.packageName) - .setUid(mPackageInfo.applicationInfo.uid) - .setButtonActions(ActionType.ACTION_NONE, ActionType.ACTION_NONE) - .done(mParent.getActivity(), true /* rebindActions */); - } -} diff --git a/src/com/android/settings/applications/AppLaunchSettings.java b/src/com/android/settings/applications/AppLaunchSettings.java index 17d8e67a0bb..fdd2d16cec9 100644 --- a/src/com/android/settings/applications/AppLaunchSettings.java +++ b/src/com/android/settings/applications/AppLaunchSettings.java @@ -28,7 +28,6 @@ import android.net.Uri; import android.os.Bundle; import android.os.UserHandle; import android.util.ArraySet; -import android.util.Log; import android.view.View; import android.view.View.OnClickListener; @@ -50,8 +49,6 @@ public class AppLaunchSettings extends AppInfoWithHeader implements OnClickListe private static final String FRAGMENT_OPEN_SUPPORTED_LINKS = "com.android.settings.applications.OpenSupportedLinks"; - public static final String KEY_PACKAGE_INFO = "pkg_info"; - private static final Intent sBrowserIntent; static { @@ -79,7 +76,8 @@ public class AppLaunchSettings extends AppInfoWithHeader implements OnClickListe mAppLinkState = findPreference(KEY_APP_LINK_STATE); mAppLinkState.setOnPreferenceClickListener(preference -> { final Bundle args = new Bundle(); - args.putParcelable(KEY_PACKAGE_INFO, this.mPackageInfo); + args.putString(ARG_PACKAGE_NAME, mPackageName); + args.putInt(ARG_PACKAGE_UID, mUserId); new SubSettingLauncher(this.getContext()) .setDestination(FRAGMENT_OPEN_SUPPORTED_LINKS) @@ -145,7 +143,6 @@ public class AppLaunchSettings extends AppInfoWithHeader implements OnClickListe private void setAppLinkStateSummary() { final int state = mPm.getIntentVerificationStatusAsUser(mPackageName, UserHandle.myUserId()); - Log.d("[sunny]", "setAppLinkStateSummary+ state=" + state); mAppLinkState.setSummary(linkStateToResourceId(state)); } diff --git a/src/com/android/settings/applications/AppOpenSupportedLinksPreferenceController.java b/src/com/android/settings/applications/AppOpenSupportedLinksPreferenceController.java deleted file mode 100644 index 479d5dd0b04..00000000000 --- a/src/com/android/settings/applications/AppOpenSupportedLinksPreferenceController.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2020 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.applications; - -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.UserHandle; -import android.text.TextUtils; -import android.util.Log; -import android.view.View; - -import androidx.annotation.VisibleForTesting; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settings.Utils; -import com.android.settings.core.BasePreferenceController; -import com.android.settingslib.widget.RadioButtonPreference; - -/** - * The radio group controller supports users to choose what kind supported links they need. - */ -public class AppOpenSupportedLinksPreferenceController extends BasePreferenceController - implements RadioButtonPreference.OnClickListener { - private static final String TAG = "OpenLinksPrefCtrl"; - private static final String KEY_LINK_OPEN_ALWAYS = "app_link_open_always"; - private static final String KEY_LINK_OPEN_ASK = "app_link_open_ask"; - private static final String KEY_LINK_OPEN_NEVER = "app_link_open_never"; - - private Context mContext; - private PackageManager mPackageManager; - private String mPackageName; - private int mCurrentIndex; - private PreferenceCategory mPreferenceCategory; - private String[] mRadioKeys = {KEY_LINK_OPEN_ALWAYS, KEY_LINK_OPEN_ASK, KEY_LINK_OPEN_NEVER}; - - @VisibleForTesting - RadioButtonPreference mAllowOpening; - @VisibleForTesting - RadioButtonPreference mAskEveryTime; - @VisibleForTesting - RadioButtonPreference mNotAllowed; - - public AppOpenSupportedLinksPreferenceController(Context context, String preferenceKey) { - super(context, preferenceKey); - mContext = context; - mPackageManager = context.getPackageManager(); - } - - /** - * @param pkg selected package name. - * @return return controller-self. - */ - public AppOpenSupportedLinksPreferenceController setInit(String pkg) { - mPackageName = pkg; - return this; - } - - @Override - public void displayPreference(PreferenceScreen screen) { - super.displayPreference(screen); - mPreferenceCategory = screen.findPreference(getPreferenceKey()); - mAllowOpening = makeRadioPreference(KEY_LINK_OPEN_ALWAYS, R.string.app_link_open_always); - final int entriesNo = getEntriesNo(); - //This to avoid the summary line wrap - mAllowOpening.setAppendixVisibility(View.GONE); - mAllowOpening.setSummary( - mContext.getResources().getQuantityString(R.plurals.app_link_open_always_summary, - entriesNo, entriesNo)); - mAskEveryTime = makeRadioPreference(KEY_LINK_OPEN_ASK, R.string.app_link_open_ask); - mNotAllowed = makeRadioPreference(KEY_LINK_OPEN_NEVER, R.string.app_link_open_never); - - final int state = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, - UserHandle.myUserId()); - mCurrentIndex = linkStateToIndex(state); - setRadioStatus(mCurrentIndex); - } - - @Override - public int getAvailabilityStatus() { - return AVAILABLE; - } - - @Override - public void onRadioButtonClicked(RadioButtonPreference preference) { - final int clickedIndex = preferenceKeyToIndex(preference.getKey()); - if (mCurrentIndex != clickedIndex) { - mCurrentIndex = clickedIndex; - setRadioStatus(mCurrentIndex); - updateAppLinkState(indexToLinkState(mCurrentIndex)); - } - } - - private RadioButtonPreference makeRadioPreference(String key, int resourceId) { - RadioButtonPreference pref = new RadioButtonPreference(mPreferenceCategory.getContext()); - pref.setKey(key); - pref.setTitle(resourceId); - pref.setOnClickListener(this); - mPreferenceCategory.addPreference(pref); - return pref; - } - - private int linkStateToIndex(int state) { - switch (state) { - case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: - return 0; // Always - case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: - return 2; // Never - default: - return 1; // Ask - } - } - - private int indexToLinkState(int index) { - switch (index) { - case 0: - return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; - case 2: - return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; - default: - return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; - } - } - - private int preferenceKeyToIndex(String key) { - for (int i = 0; i < mRadioKeys.length; i++) { - if (TextUtils.equals(key, mRadioKeys[i])) { - return i; - } - } - return 1; // Ask - } - - private void setRadioStatus(int index) { - mAllowOpening.setChecked(index == 0 ? true : false); - mAskEveryTime.setChecked(index == 1 ? true : false); - mNotAllowed.setChecked(index == 2 ? true : false); - } - - private boolean updateAppLinkState(final int newState) { - final int userId = UserHandle.myUserId(); - final int priorState = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, - userId); - - if (priorState == newState) { - return false; - } - - boolean success = mPackageManager.updateIntentVerificationStatusAsUser(mPackageName, - newState, userId); - if (success) { - // Read back the state to see if the change worked - final int updatedState = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, - userId); - success = (newState == updatedState); - } else { - Log.e(TAG, "Couldn't update intent verification status!"); - } - return success; - } - - @VisibleForTesting - int getEntriesNo() { - return Utils.getHandledDomains(mPackageManager, mPackageName).size(); - } -} diff --git a/src/com/android/settings/applications/OpenSupportedLinks.java b/src/com/android/settings/applications/OpenSupportedLinks.java index 0e1531f8d0c..84b03f173d1 100644 --- a/src/com/android/settings/applications/OpenSupportedLinks.java +++ b/src/com/android/settings/applications/OpenSupportedLinks.java @@ -15,48 +15,176 @@ */ package com.android.settings.applications; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; + import android.app.settings.SettingsEnums; -import android.content.Context; -import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.os.Bundle; +import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; +import android.view.View; import androidx.annotation.VisibleForTesting; +import androidx.appcompat.app.AlertDialog; +import androidx.preference.PreferenceCategory; import com.android.settings.R; import com.android.settings.Utils; -import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.widget.FooterPreference; +import com.android.settingslib.widget.RadioButtonPreference; /** * Display the Open Supported Links page. Allow users choose what kind supported links they need. */ -public class OpenSupportedLinks extends DashboardFragment { +public class OpenSupportedLinks extends AppInfoWithHeader implements + RadioButtonPreference.OnClickListener { private static final String TAG = "OpenSupportedLinks"; + private static final String RADIO_GROUP_KEY = "supported_links_radio_group"; private static final String FOOTER_KEY = "supported_links_footer"; + private static final String KEY_LINK_OPEN_ALWAYS = "app_link_open_always"; + private static final String KEY_LINK_OPEN_ASK = "app_link_open_ask"; + private static final String KEY_LINK_OPEN_NEVER = "app_link_open_never"; + + private static final int ALLOW_ALWAYS_OPENING = 0; + private static final int ASK_EVERY_TIME = 1; + private static final int NOT_ALLOWED_OPENING = 2; + + private int mCurrentIndex; + private String[] mRadioKeys = {KEY_LINK_OPEN_ALWAYS, KEY_LINK_OPEN_ASK, KEY_LINK_OPEN_NEVER}; @VisibleForTesting - PackageInfo mPackageInfo; + PackageManager mPackageManager; + @VisibleForTesting + PreferenceCategory mPreferenceCategory; + @VisibleForTesting + RadioButtonPreference mAllowOpening; + @VisibleForTesting + RadioButtonPreference mAskEveryTime; + @VisibleForTesting + RadioButtonPreference mNotAllowed; @Override - public void onAttach(Context context) { - super.onAttach(context); - final Bundle args = getArguments(); - mPackageInfo = (args != null) ? args.getParcelable(AppLaunchSettings.KEY_PACKAGE_INFO) - : null; - if (mPackageInfo == null) { - Log.w(TAG, "Missing PackageInfo; maybe reinstalling?"); - return; - } - use(AppHeaderPreferenceController.class).setParentFragment(this).setPackageInfo( - mPackageInfo).setLifeCycle(getSettingsLifecycle()); - use(AppOpenSupportedLinksPreferenceController.class).setInit(mPackageInfo.packageName); + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mPackageManager = getPackageManager(); + addPreferencesFromResource(R.xml.open_supported_links); + initRadioPreferencesGroup(); + updateFooterPreference(); } @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - super.onCreatePreferences(savedInstanceState, rootKey); + public int getMetricsCategory() { + return SettingsEnums.OPEN_SUPPORTED_LINKS; + } + + /** + * Here to handle radio group and generate the radios. + */ + @VisibleForTesting + void initRadioPreferencesGroup() { + mPreferenceCategory = findPreference(RADIO_GROUP_KEY); + mAllowOpening = makeRadioPreference(KEY_LINK_OPEN_ALWAYS, R.string.app_link_open_always); + final int entriesNo = getEntriesNo(); + //This to avoid the summary line wrap + mAllowOpening.setAppendixVisibility(View.GONE); + mAllowOpening.setSummary(getResources().getQuantityString( + R.plurals.app_link_open_always_summary, entriesNo, entriesNo)); + mAskEveryTime = makeRadioPreference(KEY_LINK_OPEN_ASK, R.string.app_link_open_ask); + mNotAllowed = makeRadioPreference(KEY_LINK_OPEN_NEVER, R.string.app_link_open_never); + + final int state = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, mUserId); + mCurrentIndex = linkStateToIndex(state); + setRadioStatus(mCurrentIndex); + } + + @Override + public void onRadioButtonClicked(RadioButtonPreference preference) { + final int clickedIndex = preferenceKeyToIndex(preference.getKey()); + if (mCurrentIndex != clickedIndex) { + mCurrentIndex = clickedIndex; + setRadioStatus(mCurrentIndex); + updateAppLinkState(indexToLinkState(mCurrentIndex)); + } + } + + private RadioButtonPreference makeRadioPreference(String key, int stringId) { + final RadioButtonPreference pref = new RadioButtonPreference( + mPreferenceCategory.getContext()); + pref.setKey(key); + pref.setTitle(stringId); + pref.setOnClickListener(this); + mPreferenceCategory.addPreference(pref); + return pref; + } + + @VisibleForTesting + int getEntriesNo() { + return Utils.getHandledDomains(mPackageManager, mPackageName).size(); + } + + private int linkStateToIndex(int state) { + switch (state) { + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: + return ALLOW_ALWAYS_OPENING; + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: + return NOT_ALLOWED_OPENING; + default: + return ASK_EVERY_TIME; + } + } + + private int indexToLinkState(int index) { + switch (index) { + case 0: + return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; + case 2: + return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; + default: + return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; + } + } + + private void setRadioStatus(int index) { + mAllowOpening.setChecked(index == ALLOW_ALWAYS_OPENING); + mAskEveryTime.setChecked(index == ASK_EVERY_TIME); + mNotAllowed.setChecked(index == NOT_ALLOWED_OPENING); + } + + private int preferenceKeyToIndex(String key) { + for (int i = 0; i < mRadioKeys.length; i++) { + if (TextUtils.equals(key, mRadioKeys[i])) { + return i; + } + } + return ASK_EVERY_TIME; + } + + private void updateAppLinkState(final int newState) { + final int priorState = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, + mUserId); + + if (priorState == newState) { + return; + } + + final boolean success = mPackageManager.updateIntentVerificationStatusAsUser(mPackageName, + newState, mUserId); + if (success) { + // Read back the state to see if the change worked + final int updatedState = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, + mUserId); + } else { + Log.e(TAG, "Couldn't update intent verification status!"); + } + } + + /** + * Here is handle the Footer. + */ + private void updateFooterPreference() { final FooterPreference footer = findPreference(FOOTER_KEY); if (footer == null) { Log.w(TAG, "Can't find the footer preference."); @@ -65,25 +193,9 @@ public class OpenSupportedLinks extends DashboardFragment { addLinksToFooter(footer); } - @Override - protected int getPreferenceScreenResId() { - return R.xml.open_supported_links; - } - - @Override - protected String getLogTag() { - return TAG; - } - - @Override - public int getMetricsCategory() { - return SettingsEnums.OPEN_SUPPORTED_LINKS; - } - @VisibleForTesting void addLinksToFooter(FooterPreference footer) { - final ArraySet result = Utils.getHandledDomains(getPackageManager(), - mPackageInfo.packageName); + final ArraySet result = Utils.getHandledDomains(mPackageManager, mPackageName); if (result.isEmpty()) { Log.w(TAG, "Can't find any app links."); return; @@ -94,4 +206,14 @@ public class OpenSupportedLinks extends DashboardFragment { } footer.setTitle(title); } + + @Override + protected boolean refreshUi() { + return true; + } + + @Override + protected AlertDialog createDialog(int id, int errorCode) { + return null; + } } diff --git a/tests/robotests/src/com/android/settings/applications/AppOpenSupportedLinksPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/AppOpenSupportedLinksPreferenceControllerTest.java deleted file mode 100644 index 93167354206..00000000000 --- a/tests/robotests/src/com/android/settings/applications/AppOpenSupportedLinksPreferenceControllerTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2020 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.applications; - -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; - -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.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.util.ArraySet; - -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceManager; -import androidx.preference.PreferenceScreen; - -import com.android.settings.testutils.shadow.ShadowUtils; - -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) -public class AppOpenSupportedLinksPreferenceControllerTest { - private static final String TEST_KEY = "test_key"; - private static final String TEST_DOMAIN_LINK = "aaa.bbb.ccc"; - private static final String TEST_PACKAGE = "ssl.test.package.com"; - - @Mock - private PackageManager mPackageManager; - - private Context mContext; - private PreferenceManager mPreferenceManager; - private PreferenceScreen mScreen; - private PreferenceCategory mCategory; - private AppOpenSupportedLinksPreferenceController mController; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = spy(RuntimeEnvironment.application); - doReturn(mPackageManager).when(mContext).getPackageManager(); - mPreferenceManager = new PreferenceManager(mContext); - mScreen = spy(mPreferenceManager.createPreferenceScreen(mContext)); - mCategory = spy(new PreferenceCategory(mContext)); - mController = spy(new AppOpenSupportedLinksPreferenceController(mContext, TEST_KEY)); - mController.setInit(TEST_PACKAGE); - } - - @Test - public void displayPreference_statusAlways_allowOpenChecked() { - init(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS); - - mController.displayPreference(mScreen); - - assertThat(mController.mAllowOpening.isChecked()).isTrue(); - assertThat(mController.mAskEveryTime.isChecked()).isFalse(); - assertThat(mController.mNotAllowed.isChecked()).isFalse(); - } - - @Test - public void displayPreference_statusAsk_askEveryTimeChecked() { - init(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK); - - mController.displayPreference(mScreen); - - assertThat(mController.mAllowOpening.isChecked()).isFalse(); - assertThat(mController.mAskEveryTime.isChecked()).isTrue(); - assertThat(mController.mNotAllowed.isChecked()).isFalse(); - } - - @Test - public void displayPreference_statusNever_notAllowedChecked() { - init(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER); - - mController.displayPreference(mScreen); - - assertThat(mController.mAllowOpening.isChecked()).isFalse(); - assertThat(mController.mAskEveryTime.isChecked()).isFalse(); - assertThat(mController.mNotAllowed.isChecked()).isTrue(); - } - - @Test - @Config(shadows = ShadowUtils.class) - public void getEntriesNo_oneHandledDomains_returnOne() { - initHandledDomains(); - - assertThat(mController.getEntriesNo()).isEqualTo(1); - } - - private void init(int status) { - doReturn(mCategory).when(mScreen).findPreference(any(CharSequence.class)); - doReturn(true).when(mCategory).addPreference(any(Preference.class)); - when(mPackageManager.getIntentVerificationStatusAsUser(anyString(), anyInt())).thenReturn( - status); - } - - private void initHandledDomains() { - final ArraySet domainLinks = new ArraySet<>(); - domainLinks.add(TEST_DOMAIN_LINK); - ShadowUtils.setHandledDomains(domainLinks); - } -} diff --git a/tests/robotests/src/com/android/settings/applications/OpenSupportedLinksTest.java b/tests/robotests/src/com/android/settings/applications/OpenSupportedLinksTest.java index f9d4ca83a41..ea2c4ecf50d 100644 --- a/tests/robotests/src/com/android/settings/applications/OpenSupportedLinksTest.java +++ b/tests/robotests/src/com/android/settings/applications/OpenSupportedLinksTest.java @@ -15,15 +15,27 @@ */ package com.android.settings.applications; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; + 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.anyString; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; import android.content.Context; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.util.ArraySet; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; + import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settingslib.widget.FooterPreference; @@ -31,6 +43,8 @@ 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; @@ -40,15 +54,25 @@ import org.robolectric.annotation.Config; public class OpenSupportedLinksTest { private static final String TEST_FOOTER_TITLE = "FooterTitle"; private static final String TEST_DOMAIN_LINK = "aaa.bbb.ccc"; + private static final String TEST_SUMMARY = "TestSummary"; + private static final String TEST_PACKAGE = "ssl.test.package.com"; + + @Mock + private PackageManager mPackageManager; + @Mock + private Resources mResources; private Context mContext; private TestFragment mSettings; private FooterPreference mFooter; + private PreferenceCategory mCategory; @Before public void setUp() { + MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); - mSettings = spy(new TestFragment(mContext)); + mSettings = spy(new TestFragment(mContext, mPackageManager)); + mCategory = spy(new PreferenceCategory(mContext)); mFooter = new FooterPreference.Builder(mContext).setTitle(TEST_FOOTER_TITLE).build(); } @@ -75,18 +99,68 @@ public class OpenSupportedLinksTest { assertThat(mFooter.getTitle().toString()).contains(TEST_DOMAIN_LINK); } + @Test + public void initRadioPreferencesGroup_statusAlways_allowOpenChecked() { + init(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS); + + mSettings.initRadioPreferencesGroup(); + + assertThat(mSettings.mAllowOpening.isChecked()).isTrue(); + assertThat(mSettings.mAskEveryTime.isChecked()).isFalse(); + assertThat(mSettings.mNotAllowed.isChecked()).isFalse(); + } + + @Test + public void initRadioPreferencesGroup_statusAsk_askEveryTimeChecked() { + init(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK); + + mSettings.initRadioPreferencesGroup(); + + assertThat(mSettings.mAllowOpening.isChecked()).isFalse(); + assertThat(mSettings.mAskEveryTime.isChecked()).isTrue(); + assertThat(mSettings.mNotAllowed.isChecked()).isFalse(); + } + + @Test + public void initRadioPreferencesGroup_statusNever_notAllowedChecked() { + init(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER); + + mSettings.initRadioPreferencesGroup(); + + assertThat(mSettings.mAllowOpening.isChecked()).isFalse(); + assertThat(mSettings.mAskEveryTime.isChecked()).isFalse(); + assertThat(mSettings.mNotAllowed.isChecked()).isTrue(); + } + + @Test + public void getEntriesNo_oneHandledDomains_returnOne() { + initHandledDomains(); + + assertThat(mSettings.getEntriesNo()).isEqualTo(1); + } + + private void init(int status) { + doReturn(status).when(mPackageManager).getIntentVerificationStatusAsUser(anyString(), + anyInt()); + doReturn(mCategory).when(mSettings).findPreference(any(CharSequence.class)); + doReturn(mResources).when(mSettings).getResources(); + when(mResources.getQuantityString(anyInt(), anyInt(), anyInt())).thenReturn(TEST_SUMMARY); + doReturn(true).when(mCategory).addPreference(any(Preference.class)); + } + public static class TestFragment extends OpenSupportedLinks { private final Context mContext; - public TestFragment(Context context) { + public TestFragment(Context context, PackageManager packageManager) { mContext = context; - mPackageInfo = new PackageInfo(); - mPackageInfo.packageName = "ssl.test.package.com"; - } - - @Override - protected PackageManager getPackageManager() { - return mContext.getPackageManager(); + mPackageManager = packageManager; + mPackageName = TEST_PACKAGE; } } + + private void initHandledDomains() { + final ArraySet domainLinks = new ArraySet<>(); + domainLinks.add(TEST_DOMAIN_LINK); + ShadowUtils.setHandledDomains(domainLinks); + } } From e60faf8056ce085dd4cca43bd247b4a4397f777c Mon Sep 17 00:00:00 2001 From: SongFerngWang Date: Fri, 10 Apr 2020 14:50:35 +0800 Subject: [PATCH 7/9] [5G settings UI] add UI for the 5G limited VoLTE dialog when the user disables VoLTE, UE show alert dialog for 5G disable. Bug: 151313654 Test: build pass. manual test: UI show alert dialog. Change-Id: I5ea4d59017b5d9db6f7c3d8d0ffd24d5a2c61457 --- .../Enhanced4gBasePreferenceController.java | 70 ++++++++++++++++--- 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java b/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java index cbe0912f0e9..0471f74c717 100644 --- a/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java +++ b/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java @@ -16,7 +16,10 @@ package com.android.settings.network.telephony; +import android.app.AlertDialog; +import android.app.Dialog; import android.content.Context; +import android.content.DialogInterface; import android.os.Looper; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; @@ -31,6 +34,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; +import com.android.settings.R; import com.android.settings.network.ims.VolteQueryImsState; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; @@ -50,6 +54,8 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc @VisibleForTesting Preference mPreference; private PhoneCallStateListener mPhoneStateListener; + private boolean mShow5gLimitedDialog; + private boolean mHas5gCapability; @VisibleForTesting Integer mCallState; private final List m4gLteListeners; @@ -83,6 +89,9 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc if (m4gCurrentMode != MODE_ADVANCED_CALL) { m4gCurrentMode = show4GForLTE ? MODE_4G_CALLING : MODE_VOLTE; } + + mShow5gLimitedDialog = carrierConfig.getBoolean( + CarrierConfigManager.KEY_VOLTE_5G_LIMITED_ALERT_DIALOG_BOOL); return this; } @@ -142,16 +151,13 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc if (imsMmTelManager == null) { return false; } - try { - imsMmTelManager.setAdvancedCallingSettingEnabled(isChecked); - } catch (IllegalArgumentException exception) { - Log.w(TAG, "fail to set VoLTE=" + isChecked + ". subId=" + mSubId, exception); - return false; + + if (isDialogNeeded() && !isChecked) { + show5gLimitedDialog(imsMmTelManager); + } else { + return setAdvancedCallingSettingEnabled(imsMmTelManager, isChecked); } - for (final On4gLteUpdateListener lsn : m4gLteListeners) { - lsn.on4gLteUpdated(); - } - return true; + return false; } @Override @@ -205,6 +211,10 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId); } mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE); + + final long supportedRadioBitmask = mTelephonyManager.getSupportedRadioAccessFamily(); + mHas5gCapability = + (supportedRadioBitmask & TelephonyManager.NETWORK_TYPE_BITMASK_NR) > 0; } public void unregister() { @@ -219,4 +229,46 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc public interface On4gLteUpdateListener { void on4gLteUpdated(); } + + private boolean isDialogNeeded() { + Log.d(TAG, "Has5gCapability:" + mHas5gCapability); + return mShow5gLimitedDialog && mHas5gCapability; + } + + private void show5gLimitedDialog(ImsMmTelManager imsMmTelManager) { + Log.d(TAG, "show5gLimitedDialog"); + AlertDialog.Builder builder = new AlertDialog.Builder(mContext); + DialogInterface.OnClickListener networkSettingsClickListener = + new Dialog.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Log.d(TAG, "onClick,isChecked:false"); + setAdvancedCallingSettingEnabled(imsMmTelManager, false); + updateState(mPreference); + } + }; + builder.setTitle(R.string.volte_5G_limited_title) + .setMessage(R.string.volte_5G_limited_text) + .setNeutralButton(mContext.getResources().getString( + R.string.cancel), null) + .setPositiveButton(mContext.getResources().getString( + R.string.condition_turn_off), + networkSettingsClickListener) + .create() + .show(); + } + + private boolean setAdvancedCallingSettingEnabled(ImsMmTelManager imsMmTelManager, + boolean isChecked) { + try { + imsMmTelManager.setAdvancedCallingSettingEnabled(isChecked); + } catch (IllegalArgumentException exception) { + Log.w(TAG, "fail to set VoLTE=" + isChecked + ". subId=" + mSubId, exception); + return false; + } + for (final On4gLteUpdateListener lsn : m4gLteListeners) { + lsn.on4gLteUpdated(); + } + return true; + } } From 37812984f4f82b8e0ff21b4f006abc327c931115 Mon Sep 17 00:00:00 2001 From: calvinpan Date: Tue, 14 Apr 2020 17:51:16 +0800 Subject: [PATCH 8/9] Add missing NR network mode in setPreferenceValueAndSummary Bug: 152816633 Test: atest Change-Id: I6c97ebc7c04671702a9df2a79c85b27f6f239c23 --- ...nabledNetworkModePreferenceController.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java index c1afb772427..5343709208e 100644 --- a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java +++ b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java @@ -474,10 +474,28 @@ public class EnabledNetworkModePreferenceController extends } } break; - case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO: + + case TelephonyManagerConstants.NETWORK_MODE_NR_ONLY: + case TelephonyManagerConstants.NETWORK_MODE_NR_LTE: case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA: + case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_WCDMA: + setSelectedEntry( + TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA); + setSummary(mContext.getString(R.string.network_5G) + + mContext.getString(R.string.network_recommended)); + break; + case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA: + case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM: + case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA: + case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA: case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA: - setSelectedEntry(networkMode); + setSelectedEntry( + TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA); + setSummary(mContext.getString(R.string.network_5G) + + mContext.getString(R.string.network_recommended)); + break; + case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO: + setSelectedEntry(TelephonyManagerConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO); setSummary(mContext.getString(R.string.network_5G) + mContext.getString(R.string.network_recommended)); break; From 58cc3ea7f92be1b1601fb600b66c02ca20a6a44f Mon Sep 17 00:00:00 2001 From: Peter_Liang Date: Wed, 15 Apr 2020 17:19:18 +0800 Subject: [PATCH 9/9] Revising the function name related to user shortcut type. Should add 's' into the name. Bug: 148989018 Test: manual test Change-Id: I46aadb80f4f28dc1794fc3313563c79be149e847 --- .../accessibility/SharedPreferenceUtils.java | 2 +- ...ccessibilityServicePreferenceFragment.java | 4 +- .../ToggleFeaturePreferenceFragment.java | 58 +++++++++---------- ...ScreenMagnificationPreferenceFragment.java | 38 ++++++------ 4 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/com/android/settings/accessibility/SharedPreferenceUtils.java b/src/com/android/settings/accessibility/SharedPreferenceUtils.java index b25c3d23c35..e9972918054 100644 --- a/src/com/android/settings/accessibility/SharedPreferenceUtils.java +++ b/src/com/android/settings/accessibility/SharedPreferenceUtils.java @@ -35,7 +35,7 @@ public final class SharedPreferenceUtils { } /** Returns a set of user shortcuts list to determine user preferred service shortcut. */ - public static Set getUserShortcutType(Context context) { + public static Set getUserShortcutTypes(Context context) { return getSharedPreferences(context, ACCESSIBILITY_PERF) .getStringSet(USER_SHORTCUT_TYPE, ImmutableSet.of()); } diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java index 08be8b3d26a..547a45a495e 100644 --- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java @@ -295,7 +295,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends @Override public void onToggleClicked(ShortcutPreference preference) { - final int shortcutTypes = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); if (preference.isChecked()) { if (!mToggleServiceDividerSwitchPreference.isChecked()) { preference.setChecked(false); @@ -413,7 +413,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends private void onAllowButtonFromShortcutToggleClicked() { mShortcutPreference.setChecked(true); - final int shortcutTypes = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes, mComponentName); mDialog.dismiss(); diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java index 03655a5b67b..0c83ef3de4f 100644 --- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java @@ -85,7 +85,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference protected Uri mImageUri; protected CharSequence mHtmlDescription; // Used to restore the edit dialog status. - protected int mUserShortcutTypeCache = UserShortcutType.EMPTY; + protected int mUserShortcutTypesCache = UserShortcutType.EMPTY; private static final String DRAWABLE_FOLDER = "drawable"; protected static final String KEY_USE_SERVICE_PREFERENCE = "use_service"; protected static final String KEY_GENERAL_CATEGORY = "general_categories"; @@ -93,7 +93,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference private static final String KEY_SHORTCUT_PREFERENCE = "shortcut_preference"; private static final String EXTRA_SHORTCUT_TYPE = "shortcut_type"; private TouchExplorationStateChangeListener mTouchExplorationStateChangeListener; - private int mUserShortcutType = UserShortcutType.EMPTY; + private int mUserShortcutTypes = UserShortcutType.EMPTY; private CheckBox mSoftwareTypeCheckBox; private CheckBox mHardwareTypeCheckBox; @@ -233,7 +233,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference @Override public void onSaveInstanceState(Bundle outState) { - outState.putInt(EXTRA_SHORTCUT_TYPE, mUserShortcutTypeCache); + outState.putInt(EXTRA_SHORTCUT_TYPE, mUserShortcutTypesCache); super.onSaveInstanceState(outState); } @@ -474,31 +474,31 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference } private void updateAlertDialogCheckState() { - if (mUserShortcutTypeCache != UserShortcutType.EMPTY) { + if (mUserShortcutTypesCache != UserShortcutType.EMPTY) { updateCheckStatus(mSoftwareTypeCheckBox, UserShortcutType.SOFTWARE); updateCheckStatus(mHardwareTypeCheckBox, UserShortcutType.HARDWARE); } } private void updateCheckStatus(CheckBox checkBox, @UserShortcutType int type) { - checkBox.setChecked((mUserShortcutTypeCache & type) == type); + checkBox.setChecked((mUserShortcutTypesCache & type) == type); } private void updateUserShortcutType(boolean saveChanges) { - mUserShortcutTypeCache = UserShortcutType.EMPTY; + mUserShortcutTypesCache = UserShortcutType.EMPTY; if (mSoftwareTypeCheckBox.isChecked()) { - mUserShortcutTypeCache |= UserShortcutType.SOFTWARE; + mUserShortcutTypesCache |= UserShortcutType.SOFTWARE; } if (mHardwareTypeCheckBox.isChecked()) { - mUserShortcutTypeCache |= UserShortcutType.HARDWARE; + mUserShortcutTypesCache |= UserShortcutType.HARDWARE; } if (saveChanges) { - final boolean isChanged = (mUserShortcutTypeCache != UserShortcutType.EMPTY); + final boolean isChanged = (mUserShortcutTypesCache != UserShortcutType.EMPTY); if (isChanged) { - setUserShortcutType(getPrefContext(), mUserShortcutTypeCache); + setUserShortcutType(getPrefContext(), mUserShortcutTypesCache); } - mUserShortcutType = mUserShortcutTypeCache; + mUserShortcutTypes = mUserShortcutTypesCache; } } @@ -507,7 +507,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference return; } - Set info = SharedPreferenceUtils.getUserShortcutType(context); + Set info = SharedPreferenceUtils.getUserShortcutTypes(context); final String componentName = mComponentName.flattenToString(); if (info.isEmpty()) { info = new HashSet<>(); @@ -532,7 +532,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference return context.getText(R.string.switch_off_text); } - final int shortcutType = getUserShortcutType(context, UserShortcutType.SOFTWARE); + final int shortcutTypes = getUserShortcutTypes(context, UserShortcutType.SOFTWARE); int resId = R.string.accessibility_shortcut_edit_summary_software; if (AccessibilityUtil.isGestureNavigateEnabled(context)) { resId = AccessibilityUtil.isTouchExploreEnabled(context) @@ -542,10 +542,10 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference final CharSequence softwareTitle = context.getText(resId); List list = new ArrayList<>(); - if ((shortcutType & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { + if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { list.add(softwareTitle); } - if ((shortcutType & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE) { + if ((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE) { final CharSequence hardwareTitle = context.getText( R.string.accessibility_shortcut_edit_dialog_title_hardware); list.add(hardwareTitle); @@ -559,12 +559,12 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference return AccessibilityUtil.capitalize(joinStrings); } - protected int getUserShortcutType(Context context, @UserShortcutType int defaultValue) { + protected int getUserShortcutTypes(Context context, @UserShortcutType int defaultValue) { if (mComponentName == null) { return defaultValue; } - final Set info = SharedPreferenceUtils.getUserShortcutType(context); + final Set info = SharedPreferenceUtils.getUserShortcutTypes(context); final String componentName = mComponentName.flattenToString(); final Set filtered = info.stream() .filter(str -> str.contains(componentName)) @@ -584,11 +584,11 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference } updateUserShortcutType(/* saveChanges= */ true); - AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), mUserShortcutType, + AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), mUserShortcutTypes, mComponentName); - AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), ~mUserShortcutType, + AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), ~mUserShortcutTypes, mComponentName); - mShortcutPreference.setChecked(mUserShortcutType != UserShortcutType.EMPTY); + mShortcutPreference.setChecked(mUserShortcutTypes != UserShortcutType.EMPTY); mShortcutPreference.setSummary( getShortcutTypeSummary(getPrefContext())); } @@ -599,20 +599,20 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference } // Get the user shortcut type from settings provider. - mUserShortcutType = AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(), + mUserShortcutTypes = AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(), mComponentName); - if (mUserShortcutType != UserShortcutType.EMPTY) { - setUserShortcutType(getPrefContext(), mUserShortcutType); + if (mUserShortcutTypes != UserShortcutType.EMPTY) { + setUserShortcutType(getPrefContext(), mUserShortcutTypes); } else { // Get the user shortcut type from shared_prefs if cannot get from settings provider. - mUserShortcutType = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + mUserShortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); } } private void initShortcutPreference(Bundle savedInstanceState) { // Restore the user shortcut type. if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_SHORTCUT_TYPE)) { - mUserShortcutTypeCache = savedInstanceState.getInt(EXTRA_SHORTCUT_TYPE, + mUserShortcutTypesCache = savedInstanceState.getInt(EXTRA_SHORTCUT_TYPE, UserShortcutType.EMPTY); } @@ -631,7 +631,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference return; } - final int shortcutTypes = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); mShortcutPreference.setChecked( AccessibilityUtil.hasValuesInSettings(getPrefContext(), shortcutTypes, mComponentName)); @@ -648,7 +648,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference return; } - final int shortcutTypes = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); if (preference.isChecked()) { AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes, mComponentName); @@ -662,8 +662,8 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference @Override public void onSettingsClicked(ShortcutPreference preference) { // Do not restore shortcut in shortcut chooser dialog when shortcutPreference is turned off. - mUserShortcutTypeCache = mShortcutPreference.isChecked() - ? getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE) + mUserShortcutTypesCache = mShortcutPreference.isChecked() + ? getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE) : UserShortcutType.EMPTY; } diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java index a9667bb54b1..91b8eaebd47 100644 --- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java @@ -192,7 +192,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends @Override public void onSaveInstanceState(Bundle outState) { - outState.putInt(EXTRA_SHORTCUT_TYPE, mUserShortcutTypeCache); + outState.putInt(EXTRA_SHORTCUT_TYPE, mUserShortcutTypesCache); super.onSaveInstanceState(outState); } @@ -281,7 +281,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends } private void updateAlertDialogCheckState() { - if (mUserShortcutTypeCache != UserShortcutType.EMPTY) { + if (mUserShortcutTypesCache != UserShortcutType.EMPTY) { updateCheckStatus(mSoftwareTypeCheckBox, UserShortcutType.SOFTWARE); updateCheckStatus(mHardwareTypeCheckBox, UserShortcutType.HARDWARE); updateCheckStatus(mTripleTapTypeCheckBox, UserShortcutType.TRIPLETAP); @@ -289,32 +289,32 @@ public class ToggleScreenMagnificationPreferenceFragment extends } private void updateCheckStatus(CheckBox checkBox, @UserShortcutType int type) { - checkBox.setChecked((mUserShortcutTypeCache & type) == type); + checkBox.setChecked((mUserShortcutTypesCache & type) == type); } private void updateUserShortcutType(boolean saveChanges) { - mUserShortcutTypeCache = UserShortcutType.EMPTY; + mUserShortcutTypesCache = UserShortcutType.EMPTY; if (mSoftwareTypeCheckBox.isChecked()) { - mUserShortcutTypeCache |= UserShortcutType.SOFTWARE; + mUserShortcutTypesCache |= UserShortcutType.SOFTWARE; } if (mHardwareTypeCheckBox.isChecked()) { - mUserShortcutTypeCache |= UserShortcutType.HARDWARE; + mUserShortcutTypesCache |= UserShortcutType.HARDWARE; } if (mTripleTapTypeCheckBox.isChecked()) { - mUserShortcutTypeCache |= UserShortcutType.TRIPLETAP; + mUserShortcutTypesCache |= UserShortcutType.TRIPLETAP; } if (saveChanges) { - final boolean isChanged = (mUserShortcutTypeCache != UserShortcutType.EMPTY); + final boolean isChanged = (mUserShortcutTypesCache != UserShortcutType.EMPTY); if (isChanged) { - setUserShortcutType(getPrefContext(), mUserShortcutTypeCache); + setUserShortcutType(getPrefContext(), mUserShortcutTypesCache); } - mUserShortcutType = mUserShortcutTypeCache; + mUserShortcutType = mUserShortcutTypesCache; } } private void setUserShortcutType(Context context, int type) { - Set info = SharedPreferenceUtils.getUserShortcutType(context); + Set info = SharedPreferenceUtils.getUserShortcutTypes(context); if (info.isEmpty()) { info = new HashSet<>(); } else { @@ -335,7 +335,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends return context.getText(R.string.switch_off_text); } - final int shortcutType = getUserShortcutType(context, UserShortcutType.EMPTY); + final int shortcutType = getUserShortcutTypes(context, UserShortcutType.EMPTY); int resId = R.string.accessibility_shortcut_edit_summary_software; if (AccessibilityUtil.isGestureNavigateEnabled(context)) { resId = AccessibilityUtil.isTouchExploreEnabled(context) @@ -369,8 +369,8 @@ public class ToggleScreenMagnificationPreferenceFragment extends } @Override - protected int getUserShortcutType(Context context, @UserShortcutType int defaultValue) { - final Set info = SharedPreferenceUtils.getUserShortcutType(context); + protected int getUserShortcutTypes(Context context, @UserShortcutType int defaultValue) { + final Set info = SharedPreferenceUtils.getUserShortcutTypes(context); final Set filtered = info.stream().filter( str -> str.contains(MAGNIFICATION_CONTROLLER_NAME)).collect( Collectors.toSet()); @@ -446,7 +446,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends @Override public void onToggleClicked(ShortcutPreference preference) { - final int shortcutTypes = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); if (preference.isChecked()) { optInAllMagnificationValuesToSettings(getPrefContext(), shortcutTypes); } else { @@ -458,8 +458,8 @@ public class ToggleScreenMagnificationPreferenceFragment extends @Override public void onSettingsClicked(ShortcutPreference preference) { // Do not restore shortcut in shortcut chooser dialog when shortcutPreference is turned off. - mUserShortcutTypeCache = mShortcutPreference.isChecked() - ? getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE) + mUserShortcutTypesCache = mShortcutPreference.isChecked() + ? getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE) : UserShortcutType.EMPTY; showDialog(DialogEnums.MAGNIFICATION_EDIT_SHORTCUT); } @@ -471,7 +471,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends setUserShortcutType(getPrefContext(), mUserShortcutType); } else { // Get the user shortcut type from shared_prefs if cannot get from settings provider. - mUserShortcutType = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + mUserShortcutType = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); } } @@ -487,7 +487,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends } private void updateShortcutPreference() { - final int shortcutTypes = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); mShortcutPreference.setChecked( hasMagnificationValuesInSettings(getPrefContext(), shortcutTypes)); mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));