diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 60dbb246044..4d169c561fe 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1486,6 +1486,7 @@ @@ -1910,7 +1911,6 @@ diff --git a/res/drawable/flip_camera_for_selfie.xml b/res/drawable/flip_camera_for_selfie.xml new file mode 100644 index 00000000000..dcbf9f4dc68 --- /dev/null +++ b/res/drawable/flip_camera_for_selfie.xml @@ -0,0 +1,3 @@ + + + diff --git a/res/drawable/ic_redo_24.xml b/res/drawable/ic_redo_24.xml new file mode 100644 index 00000000000..21a2020f90a --- /dev/null +++ b/res/drawable/ic_redo_24.xml @@ -0,0 +1,25 @@ + + + + \ No newline at end of file diff --git a/res/drawable/quickly_open_camera.xml b/res/drawable/quickly_open_camera.xml new file mode 100644 index 00000000000..dcbf9f4dc68 --- /dev/null +++ b/res/drawable/quickly_open_camera.xml @@ -0,0 +1,3 @@ + + + diff --git a/res/layout-land/request_manage_credentials.xml b/res/layout-land/request_manage_credentials.xml index 0c7bded8a99..fbe0bd0fbad 100644 --- a/res/layout-land/request_manage_credentials.xml +++ b/res/layout-land/request_manage_credentials.xml @@ -123,11 +123,12 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/request_manage_credentials_more" + android:textColor="?android:attr/colorBackground" android:theme="@style/Theme.CollapsingToolbar.Settings" app:backgroundTint="?android:attr/colorAccent" app:elevation="3dp" app:icon="@drawable/ic_arrow_downward" - app:iconTint="?android:attr/textColorPrimary" + app:iconTint="?android:attr/colorBackground" app:layout_anchor="@id/apps_list" app:layout_anchorGravity="bottom|center" /> diff --git a/res/layout-sw600dp/request_manage_credentials.xml b/res/layout-sw600dp/request_manage_credentials.xml index f8cf5596f03..42facd3e13f 100644 --- a/res/layout-sw600dp/request_manage_credentials.xml +++ b/res/layout-sw600dp/request_manage_credentials.xml @@ -97,11 +97,12 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/request_manage_credentials_more" + android:textColor="?android:attr/colorBackground" android:theme="@style/Theme.CollapsingToolbar.Settings" app:backgroundTint="?android:attr/colorAccent" app:elevation="3dp" app:icon="@drawable/ic_arrow_downward" - app:iconTint="?android:attr/textColorPrimary" + app:iconTint="?android:attr/colorBackground" app:layout_anchor="@id/apps_list" app:layout_anchorGravity="bottom|center" /> diff --git a/res/layout/request_manage_credentials.xml b/res/layout/request_manage_credentials.xml index c8167b6ac1d..ee697f7c2e3 100644 --- a/res/layout/request_manage_credentials.xml +++ b/res/layout/request_manage_credentials.xml @@ -67,11 +67,12 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/request_manage_credentials_more" + android:textColor="?android:attr/colorBackground" app:layout_anchor="@id/apps_list" app:layout_anchorGravity="bottom|center" app:elevation="3dp" app:icon="@drawable/ic_arrow_downward" - app:iconTint="?android:attr/textColorPrimary" + app:iconTint="?android:attr/colorBackground" app:backgroundTint="?android:attr/colorAccent" android:theme="@style/Theme.CollapsingToolbar.Settings"/> diff --git a/res/raw/lottie_flip_camera_for_selfie.json b/res/raw/lottie_adaptive_brightness.json similarity index 100% rename from res/raw/lottie_flip_camera_for_selfie.json rename to res/raw/lottie_adaptive_brightness.json diff --git a/res/raw/lottie_quick_open_camera.json b/res/raw/lottie_quick_open_camera.json deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml index c63b7c1191b..4e4ee5ddb22 100644 --- a/res/values-night/colors.xml +++ b/res/values-night/colors.xml @@ -49,5 +49,8 @@ #669df6 #5e5e5e #669df6 + + + @*android:color/ripple_material_light diff --git a/res/values/colors.xml b/res/values/colors.xml index a3a7d03d762..0fe4975550e 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -207,4 +207,7 @@ #1A73E8 + + + @*android:color/ripple_material_dark diff --git a/res/values/strings.xml b/res/values/strings.xml index 62c59e1d013..d59ae9d8e65 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6865,7 +6865,11 @@ Uninstall certificates - Remove + Remove app + + Remove this app? + + This app won\u2019t manage certificates, but it will stay on your device. Any certificates installed by the app will be uninstalled. %d URL @@ -7487,7 +7491,7 @@ Enable - Remove + Uninstall Trust @@ -10030,6 +10034,10 @@ On Off + + On + + Off On @@ -11590,9 +11598,9 @@ Work profile settings - Let personal apps identify contacts using work directory + Search for work directory contacts in personal apps - Searches and incoming calls may be visible to your IT admin + Your searches and incoming calls may be visible to your IT admin Cross-profile calendar @@ -11763,7 +11771,7 @@ Show notifications - Notification and settings will appear. + Notifications and settings will appear. @@ -12144,6 +12152,9 @@ %1$d password %1$d passwords + + \u2014 auto, fill, autofill, password @@ -12445,6 +12456,8 @@ Vibrate Mute + + To enable, first change \"Press and hold power button\" to the power menu. Network details diff --git a/res/values/styles.xml b/res/values/styles.xml index 0c62ab714ff..8b0b7a23f47 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -422,13 +422,15 @@ @@ -821,21 +826,18 @@ google-sans-medium 14sp false - ?android:attr/textColorPrimary diff --git a/res/xml/accounts_dashboard_settings.xml b/res/xml/accounts_dashboard_settings.xml index 71bfc189609..c8627e7e9e7 100644 --- a/res/xml/accounts_dashboard_settings.xml +++ b/res/xml/accounts_dashboard_settings.xml @@ -37,6 +37,7 @@ - + settings:searchable="false" + settings:lottie_rawRes="@raw/lottie_adaptive_brightness"/> - - diff --git a/res/xml/double_tap_power_settings.xml b/res/xml/double_tap_power_settings.xml index cbe2e0fea22..f4d7607c85e 100644 --- a/res/xml/double_tap_power_settings.xml +++ b/res/xml/double_tap_power_settings.xml @@ -24,7 +24,7 @@ + app:lottie_rawRes="@drawable/quickly_open_camera"/> + app:lottie_rawRes="@drawable/flip_camera_for_selfie"/> - - + + diff --git a/res/xml/nfc_and_payment_settings.xml b/res/xml/nfc_and_payment_settings.xml index 09ce27769ab..b7900f84b65 100644 --- a/res/xml/nfc_and_payment_settings.xml +++ b/res/xml/nfc_and_payment_settings.xml @@ -24,10 +24,10 @@ android:title="@string/nfc_main_switch_title" settings:controller="com.android.settings.nfc.NfcPreferenceController"/> - resolved = mPackageManager.queryIntentActivities(mRTTIntent, 0 /* flags */); - return resolved != null && !resolved.isEmpty() && isDialerSupportRTTSetting() + return resolved != null && !resolved.isEmpty() && isRttSettingSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @@ -80,17 +84,55 @@ public class RTTSettingPreferenceController extends BasePreferenceController { @Override public CharSequence getSummary() { final int option = Settings.Secure.getInt(mContext.getContentResolver(), - DIALER_RTT_CONFIGURATION, 1 /* not visible */); + DIALER_RTT_CONFIGURATION, 0 /* Invalid value */); + Log.d(TAG, "DIALER_RTT_CONFIGURATION value = " + option); return mModes[option]; } - private boolean isDialerSupportRTTSetting() { - final TelephonyManager telephonyManager = createTelephonyManagerFromSubId(); - final boolean isCarrierAndRttSupported = telephonyManager.isRttSupported() - && getBooleanCarrierConfig(CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL); + @VisibleForTesting + boolean isRttSettingSupported() { + Log.d(TAG, "isRttSettingSupported [start]"); + if (!isDefaultDialerSupportedRTT(mContext)) { + Log.d(TAG, "Dialer doesn't support RTT."); + return false; + } + // At least one PhoneAccount must have both isRttSupported and + // ignore_rtt_mode_setting_bool being true + for (PhoneAccountHandle phoneAccountHandle : + TelecomUtil.getCallCapablePhoneAccounts(mContext)) { + final int subId = + TelecomUtil.getSubIdForPhoneAccountHandle(mContext, phoneAccountHandle); + Log.d(TAG, "subscription id for the device: " + subId); - return isCarrierAndRttSupported - && TextUtils.equals(mTelecomManager.getDefaultDialerPackage(), mDialerPackage); + final boolean isRttCallingSupported = isRttSupportedByTelecom(phoneAccountHandle); + Log.d(TAG, "rtt calling supported by telecom:: " + isRttCallingSupported); + + if (isRttCallingSupported) { + PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subId); + // If IGNORE_RTT_MODE_SETTING_BOOL=true, RTT visibility is not supported because + // this means we must use the legacy Telecom setting, which does not support RTT + // visibility. + if (carrierConfig != null + && getBooleanCarrierConfig( + CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL)) { + Log.d(TAG, "RTT visibility setting is supported."); + return true; + } + Log.d(TAG, "IGNORE_RTT_MODE_SETTING_BOOL is false."); + } + } + Log.d(TAG, "isRttSettingSupported [Not support]"); + return false; + } + + private boolean isRttSupportedByTelecom(PhoneAccountHandle phoneAccountHandle) { + PhoneAccount phoneAccount = + TelecomUtil.getTelecomManager(mContext).getPhoneAccount(phoneAccountHandle); + if (phoneAccount != null && phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) { + Log.d(TAG, "Phone account has RTT capability."); + return true; + } + return false; } /** @@ -100,25 +142,24 @@ public class RTTSettingPreferenceController extends BasePreferenceController { * @return boolean value of corresponding key. */ private boolean getBooleanCarrierConfig(String key) { - final CarrierConfigManager configManager = - mContext.getSystemService(CarrierConfigManager.class); - if (configManager == null) { + if (mCarrierConfigManager == null) { // Return static default defined in CarrierConfigManager. return CarrierConfigManager.getDefaultConfig().getBoolean(key); } // If an invalid subId is used, this bundle will contain default values. final int subId = SubscriptionManager.getDefaultVoiceSubscriptionId(); - final PersistableBundle bundle = configManager.getConfigForSubId(subId); + final PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(subId); return bundle != null ? bundle.getBoolean(key) : CarrierConfigManager.getDefaultConfig().getBoolean(key); } - private TelephonyManager createTelephonyManagerFromSubId() { - final TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class); - final int subId = SubscriptionManager.getDefaultVoiceSubscriptionId(); - return telephonyManager.createForSubscriptionId(subId); + /** Returns whether is a correct default dialer which supports RTT. */ + private static boolean isDefaultDialerSupportedRTT(Context context) { + return TextUtils.equals( + context.getString(R.string.config_rtt_setting_package_name), + TelecomUtil.getTelecomManager(context).getDefaultDialerPackage()); } } diff --git a/src/com/android/settings/accessibility/rtt/TelecomUtil.java b/src/com/android/settings/accessibility/rtt/TelecomUtil.java new file mode 100644 index 00000000000..53c988ac79f --- /dev/null +++ b/src/com/android/settings/accessibility/rtt/TelecomUtil.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2021 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.accessibility.rtt; + +import android.content.Context; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.text.TextUtils; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * A util class checks some SIM card information and permissions. + */ +public abstract class TelecomUtil { + + private static final String TAG = "TelecomUtil"; + + /** Get a list of phone accounts which are call capable. */ + public static List getCallCapablePhoneAccounts(Context context) { + return Optional.ofNullable(getTelecomManager(context).getCallCapablePhoneAccounts()) + .orElse(new ArrayList<>()); + } + + /** Returns a {@link TelecomManager} instance. */ + public static TelecomManager getTelecomManager(Context context) { + return context.getApplicationContext().getSystemService(TelecomManager.class); + } + + /** Returns a subscription id of the SIM. */ + public static int getSubIdForPhoneAccountHandle( + Context context, PhoneAccountHandle phoneAccountHandle) { + Optional info = getSubscriptionInfo(context, phoneAccountHandle); + return info.map(SubscriptionInfo::getSubscriptionId) + .orElse(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } + + /** + * @return the {@link SubscriptionInfo} of the SIM if {@code phoneAccountHandle} corresponds + * to a valid SIM. Absent otherwise. + */ + private static Optional getSubscriptionInfo( + Context context, PhoneAccountHandle phoneAccountHandle) { + if (TextUtils.isEmpty(phoneAccountHandle.getId())) { + return Optional.empty(); + } + SubscriptionManager subscriptionManager = context.getSystemService( + SubscriptionManager.class); + List subscriptionInfos = + subscriptionManager.getActiveSubscriptionInfoList(); + if (subscriptionInfos == null) { + return Optional.empty(); + } + for (SubscriptionInfo info : subscriptionInfos) { + if (phoneAccountHandle.getId().startsWith(info.getIccId())) { + return Optional.of(info); + } + } + Log.d(TAG, "Failed to find SubscriptionInfo for phoneAccountHandle"); + return Optional.empty(); + } +} diff --git a/src/com/android/settings/applications/autofill/PasswordsPreferenceController.java b/src/com/android/settings/applications/autofill/PasswordsPreferenceController.java index 7cbbf6db4d1..1d67fb7539d 100644 --- a/src/com/android/settings/applications/autofill/PasswordsPreferenceController.java +++ b/src/com/android/settings/applications/autofill/PasswordsPreferenceController.java @@ -55,6 +55,7 @@ import com.android.settings.core.BasePreferenceController; import com.android.settingslib.widget.AppPreference; import java.lang.ref.WeakReference; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -76,28 +77,30 @@ public class PasswordsPreferenceController extends BasePreferenceController private LifecycleOwner mLifecycleOwner; public PasswordsPreferenceController(Context context, String preferenceKey) { - this(context, preferenceKey, - AutofillServiceInfo.getAvailableServices(context, UserHandle.myUserId())); - } - - @VisibleForTesting - public PasswordsPreferenceController( - Context context, String preferenceKey, List availableServices) { super(context, preferenceKey); mPm = context.getPackageManager(); mIconFactory = IconDrawableFactory.newInstance(mContext); + mServices = new ArrayList<>(); + } + + @OnLifecycleEvent(ON_CREATE) + void onCreate(LifecycleOwner lifecycleOwner) { + init(lifecycleOwner, AutofillServiceInfo.getAvailableServices(mContext, getUser())); + } + + @VisibleForTesting + void init(LifecycleOwner lifecycleOwner, List availableServices) { + mLifecycleOwner = lifecycleOwner; + for (int i = availableServices.size() - 1; i >= 0; i--) { final String passwordsActivity = availableServices.get(i).getPasswordsActivity(); if (TextUtils.isEmpty(passwordsActivity)) { availableServices.remove(i); } } - mServices = availableServices; - } - - @OnLifecycleEvent(ON_CREATE) - void onCreate(LifecycleOwner lifecycleOwner) { - mLifecycleOwner = lifecycleOwner; + // TODO: Reverse the loop above and add to mServices directly. + mServices.clear(); + mServices.addAll(availableServices); } @Override @@ -109,8 +112,7 @@ public class PasswordsPreferenceController extends BasePreferenceController public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); final PreferenceGroup group = screen.findPreference(getPreferenceKey()); - // TODO(b/169455298): Show work profile passwords too. - addPasswordPreferences(screen.getContext(), UserHandle.myUserId(), group); + addPasswordPreferences(screen.getContext(), getUser(), group); } private void addPasswordPreferences( @@ -126,11 +128,17 @@ public class PasswordsPreferenceController extends BasePreferenceController serviceInfo.applicationInfo, user); pref.setIcon(Utils.getSafeIcon(icon)); - pref.setIntent( - new Intent(Intent.ACTION_MAIN) - .setClassName(serviceInfo.packageName, service.getPasswordsActivity())); - // Set an empty summary to avoid a UI flicker when the value loads. - pref.setSummary(R.string.summary_placeholder); + pref.setOnPreferenceClickListener(p -> { + final Intent intent = + new Intent(Intent.ACTION_MAIN) + .setClassName( + serviceInfo.packageName, + service.getPasswordsActivity()); + prefContext.startActivityAsUser(intent, UserHandle.of(user)); + return true; + }); + // Set a placeholder summary to avoid a UI flicker when the value loads. + pref.setSummary(R.string.autofill_passwords_count_placeholder); final MutableLiveData passwordCount = new MutableLiveData<>(); passwordCount.observe( @@ -213,4 +221,9 @@ public class PasswordsPreferenceController extends BasePreferenceController } } } + + private int getUser() { + UserHandle workUser = getWorkProfileUser(); + return workUser != null ? workUser.getIdentifier() : UserHandle.myUserId(); + } } diff --git a/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java b/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java index 5dd1e43b77c..9ef66010070 100644 --- a/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java +++ b/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java @@ -159,6 +159,9 @@ public class ApplicationViewHolder extends RecyclerView.ViewHolder { if (mSwitch != null && mWidgetContainer != null) { mWidgetContainer.setOnClickListener(listener); mWidgetContainer.setFocusable(false); + mWidgetContainer.setClickable(false); + mSwitch.setFocusable(true); + mSwitch.setClickable(true); mSwitch.setChecked(checked); mSwitch.setEnabled(enabled); } diff --git a/src/com/android/settings/biometrics/BiometricEnrollActivity.java b/src/com/android/settings/biometrics/BiometricEnrollActivity.java index 26d8a45c5c9..f6396c330a7 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollActivity.java +++ b/src/com/android/settings/biometrics/BiometricEnrollActivity.java @@ -82,6 +82,10 @@ public class BiometricEnrollActivity extends InstrumentedActivity { // Intent extra. If true, parental consent will be requested before user enrollment. public static final String EXTRA_REQUIRE_PARENTAL_CONSENT = "require_consent"; + // Intent extra. If true, the screen asking the user to return the device to their parent will + // be skipped after enrollment. + public static final String EXTRA_SKIP_RETURN_TO_PARENT = "skip_return_to_parent"; + // If EXTRA_REQUIRE_PARENTAL_CONSENT was used to start the activity then the result // intent will include this extra containing a bundle of the form: // "modality" -> consented (boolean). @@ -102,6 +106,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity { private boolean mIsFaceEnrollable = false; private boolean mIsFingerprintEnrollable = false; private boolean mParentalOptionsRequired = false; + private boolean mSkipReturnToParent = false; private Bundle mParentalOptions; @Nullable private Long mGkPwHandle; @Nullable private ParentalConsentHelper mParentalConsentHelper; @@ -170,6 +175,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity { // determine what can be enrolled final boolean isSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent()); + if (mHasFeatureFace) { final FaceManager faceManager = getSystemService(FaceManager.class); final List faceProperties = @@ -193,9 +199,11 @@ public class BiometricEnrollActivity extends InstrumentedActivity { } } - // TODO(b/188847063): replace with real flag when ready - mParentalOptionsRequired = intent.getBooleanExtra( - BiometricEnrollActivity.EXTRA_REQUIRE_PARENTAL_CONSENT, false); + mParentalOptionsRequired = intent.getBooleanExtra(EXTRA_REQUIRE_PARENTAL_CONSENT, false); + mSkipReturnToParent = intent.getBooleanExtra(EXTRA_SKIP_RETURN_TO_PARENT, false); + + Log.d(TAG, "parentalOptionsRequired: " + mParentalOptionsRequired + + ", skipReturnToParent: " + mSkipReturnToParent); if (mParentalOptionsRequired && mParentalOptions == null) { mParentalConsentHelper = new ParentalConsentHelper( @@ -376,7 +384,12 @@ public class BiometricEnrollActivity extends InstrumentedActivity { private void finishOrLaunchHandToParent(int resultCode) { if (mParentalOptionsRequired) { - launchHandoffToParent(); + if (!mSkipReturnToParent) { + launchHandoffToParent(); + } else { + setResult(RESULT_OK, newResultIntent()); + finish(); + } } else { setResult(resultCode); finish(); diff --git a/src/com/android/settings/biometrics/face/FaceEnrollEducation.java b/src/com/android/settings/biometrics/face/FaceEnrollEducation.java index 65ab2e7c783..f915059407c 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollEducation.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollEducation.java @@ -215,8 +215,10 @@ public class FaceEnrollEducation extends BiometricEnrollBase { } protected void onSkipButtonClick(View view) { - setResult(RESULT_SKIP); - finish(); + if (!BiometricUtils.tryStartingNextBiometricEnroll(this, ENROLL_NEXT_BIOMETRIC_REQUEST)) { + setResult(RESULT_SKIP); + finish(); + } } @Override diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java index 9b19ef796c0..714e210f9f1 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java @@ -36,6 +36,8 @@ import android.os.Vibrator; import android.text.TextUtils; import android.util.Log; import android.view.MotionEvent; +import android.view.OrientationEventListener; +import android.view.Surface; import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -116,6 +118,9 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { private AccessibilityManager mAccessibilityManager; private boolean mIsAccessibilityEnabled; + private OrientationEventListener mOrientationEventListener; + private int mPreviousRotation = 0; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -128,6 +133,8 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { mAccessibilityManager = getSystemService(AccessibilityManager.class); mIsAccessibilityEnabled = mAccessibilityManager.isEnabled(); + listenOrientationEvent(); + if (mCanAssumeUdfps) { if (BiometricUtils.isReverseLandscape(getApplicationContext())) { setContentView(R.layout.udfps_enroll_enrolling_land); @@ -255,6 +262,12 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { stopIconAnimation(); } + @Override + protected void onDestroy() { + stopListenOrientationEvent(); + super.onDestroy(); + } + private void animateProgress(int progress) { if (mCanAssumeUdfps) { // UDFPS animations are owned by SystemUI @@ -451,6 +464,31 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { } } + private void listenOrientationEvent() { + mOrientationEventListener = new OrientationEventListener(this) { + @Override + public void onOrientationChanged(int orientation) { + final int currentRotation = getDisplay().getRotation(); + if ((mPreviousRotation == Surface.ROTATION_90 + && currentRotation == Surface.ROTATION_270) || ( + mPreviousRotation == Surface.ROTATION_270 + && currentRotation == Surface.ROTATION_90)) { + mPreviousRotation = currentRotation; + recreate(); + } + } + }; + mOrientationEventListener.enable(); + mPreviousRotation = getDisplay().getRotation(); + } + + private void stopListenOrientationEvent() { + if (mOrientationEventListener != null) { + mOrientationEventListener.disable(); + } + mOrientationEventListener = null; + } + private final Animator.AnimatorListener mProgressAnimationListener = new Animator.AnimatorListener() { diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintErrorDialog.java b/src/com/android/settings/biometrics/fingerprint/FingerprintErrorDialog.java index e4d86a199e7..fa929514173 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintErrorDialog.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintErrorDialog.java @@ -45,7 +45,7 @@ public class FingerprintErrorDialog extends BiometricErrorDialog { // This message happens when the underlying crypto layer decides to revoke the // enrollment auth token. return R.string.security_settings_fingerprint_enroll_error_timeout_dialog_message; - case FingerprintManager.FINGERPRINT_ERROR_BAD_CALIBARTION: + case FingerprintManager.FINGERPRINT_ERROR_BAD_CALIBRATION: return R.string.security_settings_fingerprint_bad_calibration; default: // There's nothing specific to tell the user about. Ask them to try again. diff --git a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java index 1ad322aab97..21813099237 100644 --- a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java +++ b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java @@ -229,14 +229,18 @@ public abstract class DeviceListPreferenceFragment extends @VisibleForTesting void enableScanning() { // BluetoothAdapter already handles repeated scan requests - startScanning(); - mScanEnabled = true; + if (!mScanEnabled) { + startScanning(); + mScanEnabled = true; + } } @VisibleForTesting void disableScanning() { - stopScanning(); - mScanEnabled = false; + if (mScanEnabled) { + stopScanning(); + mScanEnabled = false; + } } @Override diff --git a/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentController.java b/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentController.java index 17958c96010..ee0021ec951 100644 --- a/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentController.java +++ b/src/com/android/settings/connecteddevice/NfcAndPaymentFragmentController.java @@ -54,9 +54,9 @@ public class NfcAndPaymentFragmentController extends BasePreferenceController { public CharSequence getSummary() { if (mNfcAdapter != null) { if (mNfcAdapter.isEnabled()) { - return mContext.getText(R.string.switch_on_text); + return mContext.getText(R.string.nfc_setting_on); } else { - return mContext.getText(R.string.switch_off_text); + return mContext.getText(R.string.nfc_setting_off); } } return null; diff --git a/src/com/android/settings/core/SettingsBaseActivity.java b/src/com/android/settings/core/SettingsBaseActivity.java index 74494a75117..e8a7f36908a 100644 --- a/src/com/android/settings/core/SettingsBaseActivity.java +++ b/src/com/android/settings/core/SettingsBaseActivity.java @@ -48,8 +48,7 @@ import com.google.android.setupcompat.util.WizardManagerHelper; import com.google.android.setupdesign.util.ThemeHelper; /** Base activity for Settings pages */ -public class SettingsBaseActivity extends FragmentActivity implements CategoryHandler, - AppBarLayout.OnOffsetChangedListener { +public class SettingsBaseActivity extends FragmentActivity implements CategoryHandler { /** * What type of page transition should be apply. @@ -59,16 +58,12 @@ public class SettingsBaseActivity extends FragmentActivity implements CategoryHa protected static final boolean DEBUG_TIMING = false; private static final String TAG = "SettingsBaseActivity"; private static final int DEFAULT_REQUEST = -1; - private static final int FULLY_EXPANDED_OFFSET = 0; - private static final int TOOLBAR_MAX_LINE_NUMBER = 2; private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f; - private static final String KEY_IS_TOOLBAR_COLLAPSED = "is_toolbar_collapsed"; protected CategoryMixin mCategoryMixin; protected CollapsingToolbarLayout mCollapsingToolbarLayout; protected AppBarLayout mAppBarLayout; private Toolbar mToolbar; - private boolean mIsToolbarCollapsed; @Override public CategoryMixin getCategoryMixin() { @@ -106,11 +101,9 @@ public class SettingsBaseActivity extends FragmentActivity implements CategoryHa super.setContentView(R.layout.collapsing_toolbar_base_layout); mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar); mAppBarLayout = findViewById(R.id.app_bar); - mAppBarLayout.addOnOffsetChangedListener(this); - if (savedInstanceState != null) { - mIsToolbarCollapsed = savedInstanceState.getBoolean(KEY_IS_TOOLBAR_COLLAPSED); + if (mCollapsingToolbarLayout != null) { + mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER); } - initCollapsingToolbar(); disableCollapsingToolbarLayoutScrollingBehavior(); } else { super.setContentView(R.layout.settings_base_layout); @@ -202,23 +195,6 @@ public class SettingsBaseActivity extends FragmentActivity implements CategoryHa } } - @Override - public void onOffsetChanged(AppBarLayout appBarLayout, int offset) { - if (offset == FULLY_EXPANDED_OFFSET) { - mIsToolbarCollapsed = false; - } else { - mIsToolbarCollapsed = true; - } - } - - @Override - protected void onSaveInstanceState(@NonNull Bundle outState) { - super.onSaveInstanceState(outState); - if (isChangingConfigurations()) { - outState.putBoolean(KEY_IS_TOOLBAR_COLLAPSED, mIsToolbarCollapsed); - } - } - /** * SubSetting page should show a toolbar by default. If the page wouldn't show a toolbar, * override this method and return false value. @@ -285,43 +261,4 @@ public class SettingsBaseActivity extends FragmentActivity implements CategoryHa private int getTransitionType(Intent intent) { return intent.getIntExtra(EXTRA_PAGE_TRANSITION_TYPE, TransitionType.TRANSITION_NONE); } - - @SuppressWarnings("RestrictTo") - private void initCollapsingToolbar() { - if (mCollapsingToolbarLayout == null || mAppBarLayout == null) { - return; - } - mCollapsingToolbarLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, - int oldLeft, int oldTop, int oldRight, int oldBottom) { - v.removeOnLayoutChangeListener(this); - if (mIsToolbarCollapsed) { - return; - } - final int count = mCollapsingToolbarLayout.getLineCount(); - if (count > TOOLBAR_MAX_LINE_NUMBER) { - final ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams(); - lp.height = getResources() - .getDimensionPixelSize(R.dimen.toolbar_three_lines_height); - mCollapsingToolbarLayout.setScrimVisibleHeightTrigger( - getResources().getDimensionPixelSize( - R.dimen.scrim_visible_height_trigger_three_lines)); - mCollapsingToolbarLayout.setLayoutParams(lp); - mCollapsingToolbarLayout - .setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER); - } else if (count == TOOLBAR_MAX_LINE_NUMBER) { - final ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams(); - lp.height = getResources() - .getDimensionPixelSize(R.dimen.toolbar_two_lines_height); - mCollapsingToolbarLayout.setScrimVisibleHeightTrigger( - getResources().getDimensionPixelSize( - R.dimen.scrim_visible_height_trigger_two_lines)); - mCollapsingToolbarLayout.setLayoutParams(lp); - mCollapsingToolbarLayout - .setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER); - } - } - }); - } } diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java index 1e0a8dde1b3..82d524d9f06 100644 --- a/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java +++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java @@ -21,6 +21,7 @@ import static android.content.Intent.EXTRA_USER_ID; import android.annotation.IntDef; import android.app.Activity; import android.content.Context; +import android.content.res.ColorStateList; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; @@ -113,6 +114,7 @@ public abstract class ProfileSelectFragment extends DashboardFragment { viewPager.setAdapter(new ProfileSelectFragment.ViewPagerAdapter(this)); final TabLayout tabs = tabContainer.findViewById(R.id.tabs); tabs.setupWithViewPager(viewPager); + setupTabTextColor(tabs); tabContainer.setVisibility(View.VISIBLE); final TabLayout.Tab tab = tabs.getTabAt(selectedTab); tab.select(); @@ -129,6 +131,30 @@ public abstract class ProfileSelectFragment extends DashboardFragment { return mContentView; } + /** + * TabLayout uses ColorStateList of 2 states, selected state and empty state. + * It's expected to use textColorSecondary default state color as empty state tabTextColor. + * + * However, TabLayout uses textColorSecondary by a not expected state. + * This method sets tabTextColor with the color of expected textColorSecondary state. + */ + private void setupTabTextColor(TabLayout tabLayout) { + final ColorStateList defaultColorStateList = tabLayout.getTabTextColors(); + final ColorStateList resultColorStateList = new ColorStateList( + new int[][]{ + new int[]{android.R.attr.state_selected}, + new int[]{} + }, + new int[] { + defaultColorStateList.getColorForState(new int[]{android.R.attr.state_selected}, + Utils.getColorAttrDefaultColor(getContext(), + com.android.internal.R.attr.colorAccentPrimaryVariant)), + Utils.getColorAttrDefaultColor(getContext(), android.R.attr.textColorSecondary) + } + ); + tabLayout.setTabTextColors(resultColorStateList); + } + @Override public int getMetricsCategory() { return METRICS_CATEGORY_UNKNOWN; diff --git a/src/com/android/settings/development/qstile/DevelopmentTiles.java b/src/com/android/settings/development/qstile/DevelopmentTiles.java index c55d0cb354d..764c83ef64a 100644 --- a/src/com/android/settings/development/qstile/DevelopmentTiles.java +++ b/src/com/android/settings/development/qstile/DevelopmentTiles.java @@ -48,8 +48,6 @@ import android.widget.Toast; import androidx.annotation.VisibleForTesting; import com.android.internal.app.LocalePicker; -import com.android.internal.inputmethod.Completable; -import com.android.internal.inputmethod.ResultCallbacks; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.view.IInputMethodManager; import com.android.settings.R; @@ -262,13 +260,9 @@ public abstract class DevelopmentTiles extends TileService { return false; } - @VisibleForTesting - boolean isImeTraceEnabled() { + private boolean isImeTraceEnabled() { try { - // TODO(b/175742251): Get rid of dependency on IInputMethodManager - final Completable.Boolean value = Completable.createBoolean(); - mInputMethodManager.isImeTraceEnabled(ResultCallbacks.of(value)); - return Completable.getResult(value); + return mInputMethodManager.isImeTraceEnabled(); } catch (RemoteException e) { Log.e(TAG, "Could not get ime trace status, defaulting to false.", e); } @@ -328,16 +322,13 @@ public abstract class DevelopmentTiles extends TileService { } } - protected void setImeTraceEnabled(boolean isEnabled) { + private void setImeTraceEnabled(boolean isEnabled) { try { - // TODO(b/175742251): Get rid of dependency on IInputMethodManager - final Completable.Void value = Completable.createVoid(); if (isEnabled) { - mInputMethodManager.startImeTrace(ResultCallbacks.of(value)); + mInputMethodManager.startImeTrace(); } else { - mInputMethodManager.stopImeTrace(ResultCallbacks.of(value)); + mInputMethodManager.stopImeTrace(); } - Completable.getResult(value); } catch (RemoteException e) { Log.e(TAG, "Could not set ime trace status." + e.toString()); } diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java index 22ea98fda3e..fd9ae8c5d8f 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java @@ -386,8 +386,6 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle + otherData.documentsAndOtherSize + otherData.trashSize + otherData.allAppsExceptGamesSize; - attributedSize += otherData.externalStats.totalBytes - - otherData.externalStats.appBytes; attributedSize -= otherData.duplicateCodeSize; } diff --git a/src/com/android/settings/display/SmartAutoRotateBatterySaverController.java b/src/com/android/settings/display/SmartAutoRotateBatterySaverController.java index 4e083029ce9..9d4645e1fd0 100644 --- a/src/com/android/settings/display/SmartAutoRotateBatterySaverController.java +++ b/src/com/android/settings/display/SmartAutoRotateBatterySaverController.java @@ -50,7 +50,7 @@ public class SmartAutoRotateBatterySaverController extends BasePreferenceControl if (mPreference == null) { return; } - mPreference.setVisible(isPowerSaveMode()); + mPreference.setVisible(isAvailable()); updateState(mPreference); } }; diff --git a/src/com/android/settings/display/SmartAutoRotateCameraStateController.java b/src/com/android/settings/display/SmartAutoRotateCameraStateController.java index a17a903532e..39576a9dfee 100644 --- a/src/com/android/settings/display/SmartAutoRotateCameraStateController.java +++ b/src/com/android/settings/display/SmartAutoRotateCameraStateController.java @@ -45,7 +45,7 @@ public class SmartAutoRotateCameraStateController extends BasePreferenceControll mPrivacyManager = SensorPrivacyManager.getInstance(context); mPrivacyManager.addSensorPrivacyListener(CAMERA, (sensor, enabled) -> { if (mPreference != null) { - mPreference.setVisible(enabled); + mPreference.setVisible(isAvailable()); } updateState(mPreference); }); diff --git a/src/com/android/settings/display/SmartAutoRotatePermissionController.java b/src/com/android/settings/display/SmartAutoRotatePermissionController.java index caa306d6a9d..aa6a96d55da 100644 --- a/src/com/android/settings/display/SmartAutoRotatePermissionController.java +++ b/src/com/android/settings/display/SmartAutoRotatePermissionController.java @@ -23,19 +23,24 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; +import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnResume; import com.android.settingslib.widget.BannerMessagePreference; /** * The controller of camera based rotate permission warning preference. The preference appears when * the camera permission is missing for the camera based rotation feature. */ -public class SmartAutoRotatePermissionController extends BasePreferenceController { +public class SmartAutoRotatePermissionController extends BasePreferenceController implements + LifecycleObserver, OnResume { private final Intent mIntent; + private BannerMessagePreference mPreference; public SmartAutoRotatePermissionController(Context context, String key) { super(context, key); @@ -48,15 +53,27 @@ public class SmartAutoRotatePermissionController extends BasePreferenceControlle @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); - final BannerMessagePreference preference = - (BannerMessagePreference) screen.findPreference(getPreferenceKey()); - preference + mPreference = screen.findPreference(getPreferenceKey()); + mPreference .setPositiveButtonText(R.string.auto_rotate_manage_permission_button) .setPositiveButtonOnClickListener(v -> { mContext.startActivity(mIntent); }); } + @Override + public void onResume() { + updateState(mPreference); + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + if (preference != null) { + preference.setVisible(isAvailable()); + } + } + @Override @AvailabilityStatus public int getAvailabilityStatus() { diff --git a/src/com/android/settings/gestures/PreventRingingParentPreferenceController.java b/src/com/android/settings/gestures/PreventRingingParentPreferenceController.java index b67943817ee..b3b39fbd7e5 100644 --- a/src/com/android/settings/gestures/PreventRingingParentPreferenceController.java +++ b/src/com/android/settings/gestures/PreventRingingParentPreferenceController.java @@ -37,10 +37,15 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; +import com.google.common.annotations.VisibleForTesting; + /** The controller manages the behaviour of the Prevent Ringing gesture setting. */ public class PreventRingingParentPreferenceController extends TogglePreferenceController implements LifecycleObserver, OnStart, OnStop { + @VisibleForTesting + static final int KEY_CHORD_POWER_VOLUME_UP_MUTE_TOGGLE = 1; + final String SECURE_KEY = VOLUME_HUSH_GESTURE; private PrimarySwitchPreference mPreference; @@ -59,6 +64,10 @@ public class PreventRingingParentPreferenceController extends TogglePreferenceCo @Override public boolean isChecked() { + if (!isVolumePowerKeyChordSetToHush()) { + return false; + } + final int preventRinging = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE, Settings.Secure.VOLUME_HUSH_VIBRATE); @@ -85,25 +94,47 @@ public class PreventRingingParentPreferenceController extends TogglePreferenceCo final int value = Settings.Secure.getInt( mContext.getContentResolver(), SECURE_KEY, VOLUME_HUSH_VIBRATE); CharSequence summary; - switch (value) { - case VOLUME_HUSH_VIBRATE: - summary = mContext.getText(R.string.prevent_ringing_option_vibrate_summary); - break; - case VOLUME_HUSH_MUTE: - summary = mContext.getText(R.string.prevent_ringing_option_mute_summary); - break; - // VOLUME_HUSH_OFF - default: - summary = mContext.getText(R.string.switch_off_text); + if (isVolumePowerKeyChordSetToHush()) { + switch (value) { + case VOLUME_HUSH_VIBRATE: + summary = mContext.getText(R.string.prevent_ringing_option_vibrate_summary); + break; + case VOLUME_HUSH_MUTE: + summary = mContext.getText(R.string.prevent_ringing_option_mute_summary); + break; + // VOLUME_HUSH_OFF + default: + summary = mContext.getText(R.string.switch_off_text); + } + preference.setEnabled(true); + mPreference.setSwitchEnabled(true); + } else { + summary = mContext.getText(R.string.prevent_ringing_option_unavailable_lpp_summary); + preference.setEnabled(false); + mPreference.setSwitchEnabled(false); } + preference.setSummary(summary); } @Override public int getAvailabilityStatus() { - return mContext.getResources().getBoolean( - com.android.internal.R.bool.config_volumeHushGestureEnabled) - ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_volumeHushGestureEnabled)) { + return UNSUPPORTED_ON_DEVICE; + } + if (isVolumePowerKeyChordSetToHush()) { + return AVAILABLE; + } + if (mContext.getResources().getBoolean( + com.android.internal + .R.bool.config_longPressOnPowerForAssistantSettingAvailable)) { + // The power + volume key chord is not set to hush gesture - it's been disabled + // by long press power for Assistant. + return DISABLED_DEPENDENT_SETTING; + } + + return UNSUPPORTED_ON_DEVICE; } @Override @@ -121,9 +152,26 @@ public class PreventRingingParentPreferenceController extends TogglePreferenceCo } } + /** + * Returns true if power + volume up key chord is actually set to "mute toggle". If not, + * this setting will have no effect and should be disabled. + * + * This handles the condition when long press on power for Assistant changes power + volume + * chord to power menu and this setting needs to be disabled. + */ + private boolean isVolumePowerKeyChordSetToHush() { + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.KEY_CHORD_POWER_VOLUME_UP, + mContext.getResources().getInteger( + com.android.internal.R.integer.config_keyChordPowerVolumeUp)) + == KEY_CHORD_POWER_VOLUME_UP_MUTE_TOGGLE; + } + private class SettingObserver extends ContentObserver { private final Uri mVolumeHushGestureUri = Settings.Secure.getUriFor( Settings.Secure.VOLUME_HUSH_GESTURE); + private final Uri mKeyChordVolumePowerUpUri = Settings.Global.getUriFor( + Settings.Global.KEY_CHORD_POWER_VOLUME_UP); private final Preference mPreference; @@ -133,6 +181,7 @@ public class PreventRingingParentPreferenceController extends TogglePreferenceCo } public void register(ContentResolver cr) { + cr.registerContentObserver(mKeyChordVolumePowerUpUri, false, this); cr.registerContentObserver(mVolumeHushGestureUri, false, this); } @@ -143,7 +192,8 @@ public class PreventRingingParentPreferenceController extends TogglePreferenceCo @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); - if (uri == null || mVolumeHushGestureUri.equals(uri)) { + if (uri == null || mVolumeHushGestureUri.equals(uri) + || mKeyChordVolumePowerUpUri.equals(uri)) { updateState(mPreference); } } diff --git a/src/com/android/settings/location/RecentLocationRequestSeeAllFragment.java b/src/com/android/settings/location/RecentLocationRequestSeeAllFragment.java index 3f0defd1ac6..7fd66435c7a 100644 --- a/src/com/android/settings/location/RecentLocationRequestSeeAllFragment.java +++ b/src/com/android/settings/location/RecentLocationRequestSeeAllFragment.java @@ -24,11 +24,9 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.profileselector.ProfileSelectFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; -/** Dashboard Fragment to display all recent location requests, sorted by recency. */ -@SearchIndexable +/** @deprecated Use {@link RecentLocationAccessSeeAllFragment} instead. */ +@Deprecated public class RecentLocationRequestSeeAllFragment extends DashboardFragment { private static final String TAG = "RecentLocationReqAll"; public static final String PATH = @@ -99,10 +97,4 @@ public class RecentLocationRequestSeeAllFragment extends DashboardFragment { R.string.menu_hide_system); updateMenu(); } - - /** - * For Search. - */ - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.location_recent_requests_see_all); } diff --git a/src/com/android/settings/network/SubscriptionsPreferenceController.java b/src/com/android/settings/network/SubscriptionsPreferenceController.java index e88cded175e..7c0fc29736a 100644 --- a/src/com/android/settings/network/SubscriptionsPreferenceController.java +++ b/src/com/android/settings/network/SubscriptionsPreferenceController.java @@ -603,7 +603,11 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl public String getNetworkType(Context context, Config config, TelephonyDisplayInfo telephonyDisplayInfo, int subId) { String iconKey = getIconKey(telephonyDisplayInfo); - int resId = mapIconSets(config).get(iconKey).dataContentDescription; + MobileIconGroup iconGroup = mapIconSets(config).get(iconKey); + int resId = 0; + if (iconGroup != null) { + resId = iconGroup.dataContentDescription; + } return resId != 0 ? SubscriptionManager.getResourcesForSubId(context, subId).getString(resId) : ""; diff --git a/src/com/android/settings/password/SetNewPasswordActivity.java b/src/com/android/settings/password/SetNewPasswordActivity.java index 87411751bff..22825872128 100644 --- a/src/com/android/settings/password/SetNewPasswordActivity.java +++ b/src/com/android/settings/password/SetNewPasswordActivity.java @@ -134,6 +134,8 @@ public class SetNewPasswordActivity extends Activity implements SetNewPasswordCo intent.putExtra(EXTRA_KEY_IS_CALLING_APP_ADMIN, true); } intent.putExtra(EXTRA_KEY_DEVICE_PASSWORD_REQUIREMENT_ONLY, mDevicePasswordRequirementOnly); + // Copy the setup wizard intent extra to the intent. + WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent); startActivity(intent); finish(); } diff --git a/src/com/android/settings/security/CredentialManagementAppButtonsController.java b/src/com/android/settings/security/CredentialManagementAppButtonsController.java index b296f379a55..250dd133e81 100644 --- a/src/com/android/settings/security/CredentialManagementAppButtonsController.java +++ b/src/com/android/settings/security/CredentialManagementAppButtonsController.java @@ -16,8 +16,11 @@ package com.android.settings.security; +import android.app.Dialog; import android.app.admin.DevicePolicyEventLogger; +import android.app.settings.SettingsEnums; import android.content.Context; +import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; @@ -25,12 +28,15 @@ import android.security.IKeyChainService; import android.security.KeyChain; import android.stats.devicepolicy.DevicePolicyEnums; import android.util.Log; +import android.view.View; +import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; +import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settingslib.widget.ActionButtonsPreference; import java.util.concurrent.ExecutorService; @@ -48,9 +54,16 @@ public class CredentialManagementAppButtonsController extends BasePreferenceCont private final Handler mHandler = new Handler(Looper.getMainLooper()); private boolean mHasCredentialManagerPackage; private Fragment mFragment; + private final int mRemoveIcon; public CredentialManagementAppButtonsController(Context context, String preferenceKey) { super(context, preferenceKey); + if (context.getResources().getConfiguration().getLayoutDirection() + == View.LAYOUT_DIRECTION_RTL) { + mRemoveIcon = R.drawable.ic_redo_24; + } else { + mRemoveIcon = R.drawable.ic_undo_24; + } } public void setParentFragment(Fragment fragment) { @@ -84,8 +97,8 @@ public class CredentialManagementAppButtonsController extends BasePreferenceCont .setButton1Icon(R.drawable.ic_upload) .setButton1OnClickListener(view -> uninstallCertificates()) .setButton2Text(R.string.remove_credential_management_app) - .setButton2Icon(R.drawable.ic_delete) - .setButton2OnClickListener(view -> removeCredentialManagementApp()); + .setButton2Icon(mRemoveIcon) + .setButton2OnClickListener(view -> showRemoveCredentialManagementAppDialog()); } } @@ -103,18 +116,54 @@ public class CredentialManagementAppButtonsController extends BasePreferenceCont }); } - private void removeCredentialManagementApp() { - mExecutor.execute(() -> { - try { - IKeyChainService service = KeyChain.bind(mContext).getService(); - service.removeCredentialManagementApp(); - DevicePolicyEventLogger - .createEvent(DevicePolicyEnums.CREDENTIAL_MANAGEMENT_APP_REMOVED) - .write(); - mFragment.getActivity().finish(); - } catch (InterruptedException | RemoteException e) { - Log.e(TAG, "Unable to remove the credential management app"); - } - }); + private void showRemoveCredentialManagementAppDialog() { + final RemoveCredentialManagementAppDialog dialog = + RemoveCredentialManagementAppDialog.newInstance(); + dialog.show(mFragment.getParentFragmentManager(), + RemoveCredentialManagementAppDialog.class.getName()); } -} + + /** + * Implements an AlertDialog for confirming that a user wants to remove the credential + * management app. The app will no longer be able to manage certificates, but it will stay on + * the device. All certificates installed by the credential management app will be uninstalled. + */ + public static class RemoveCredentialManagementAppDialog extends InstrumentedDialogFragment { + + public static RemoveCredentialManagementAppDialog newInstance() { + return new RemoveCredentialManagementAppDialog(); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new AlertDialog.Builder(getContext(), R.style.Theme_AlertDialog) + .setTitle(R.string.remove_credential_management_app_dialog_title) + .setMessage(R.string.remove_credential_management_app_dialog_message) + .setPositiveButton(R.string.remove_credential_management_app, + (dialog, which) -> removeCredentialManagementApp()) + .setNegativeButton(R.string.cancel, (dialog, which) -> dismiss()) + .create(); + } + + private void removeCredentialManagementApp() { + final ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.execute(() -> { + try { + IKeyChainService service = KeyChain.bind(getContext()).getService(); + service.removeCredentialManagementApp(); + DevicePolicyEventLogger + .createEvent(DevicePolicyEnums.CREDENTIAL_MANAGEMENT_APP_REMOVED) + .write(); + getParentFragment().getActivity().finish(); + } catch (InterruptedException | RemoteException e) { + Log.e(TAG, "Unable to remove the credential management app"); + } + }); + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.CREDENTIAL_MANAGEMENT_APP_REMOVE_APP; + } + } +} \ No newline at end of file diff --git a/src/com/android/settings/security/RequestManageCredentials.java b/src/com/android/settings/security/RequestManageCredentials.java index cda97da17d3..1a8da671a2c 100644 --- a/src/com/android/settings/security/RequestManageCredentials.java +++ b/src/com/android/settings/security/RequestManageCredentials.java @@ -288,7 +288,7 @@ public class RequestManageCredentials extends Activity { // On down scroll, hide text in floating action button by setting // extended to false. if (dy > 0 && mExtendedFab.getVisibility() == View.VISIBLE) { - mExtendedFab.setExtended(false); + mExtendedFab.shrink(); } if (isRecyclerScrollable()) { mExtendedFab.show(); diff --git a/src/com/android/settings/widget/SettingsMainSwitchPreference.java b/src/com/android/settings/widget/SettingsMainSwitchPreference.java index f0e8d95b899..f1eb603a719 100644 --- a/src/com/android/settings/widget/SettingsMainSwitchPreference.java +++ b/src/com/android/settings/widget/SettingsMainSwitchPreference.java @@ -50,7 +50,6 @@ public class SettingsMainSwitchPreference extends TwoStatePreference implements private SettingsMainSwitchBar mMainSwitchBar; private CharSequence mTitle; - private boolean mIsVisible; private EnforcedAdmin mEnforcedAdmin; private RestrictedPreferenceHelper mRestrictedHelper; @@ -87,7 +86,7 @@ public class SettingsMainSwitchPreference extends TwoStatePreference implements } mMainSwitchBar = (SettingsMainSwitchBar) holder.findViewById(R.id.main_switch_bar); initMainSwitchBar(); - if (mIsVisible) { + if (isVisible()) { mMainSwitchBar.show(); if (mMainSwitchBar.isChecked() != isChecked()) { setChecked(isChecked()); @@ -101,7 +100,6 @@ public class SettingsMainSwitchPreference extends TwoStatePreference implements private void init(Context context, AttributeSet attrs) { setLayoutResource(R.layout.preference_widget_main_switch); mSwitchChangeListeners.add(this); - mIsVisible = true; if (attrs != null) { final TypedArray a = context.obtainStyledAttributes(attrs, @@ -151,7 +149,7 @@ public class SettingsMainSwitchPreference extends TwoStatePreference implements * Show the MainSwitchBar */ public void show() { - mIsVisible = true; + setVisible(true); if (mMainSwitchBar != null) { mMainSwitchBar.show(); } @@ -161,7 +159,7 @@ public class SettingsMainSwitchPreference extends TwoStatePreference implements * Hide the MainSwitchBar */ public void hide() { - mIsVisible = false; + setVisible(false); if (mMainSwitchBar != null) { mMainSwitchBar.hide(); } diff --git a/tests/robotests/src/com/android/settings/accessibility/RTTSettingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/RTTSettingPreferenceControllerTest.java index 5a90098ca6f..ffc2e85a3d8 100644 --- a/tests/robotests/src/com/android/settings/accessibility/RTTSettingPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/RTTSettingPreferenceControllerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2021 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. @@ -25,22 +25,15 @@ import static org.robolectric.Shadows.shadowOf; import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; -import android.os.PersistableBundle; -import android.telecom.TelecomManager; -import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; import androidx.test.core.app.ApplicationProvider; -import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import com.android.settings.testutils.ResolveInfoBuilder; 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.shadows.ShadowPackageManager; @@ -51,72 +44,40 @@ public class RTTSettingPreferenceControllerTest { private ShadowPackageManager mShadowPackageManager; private RTTSettingPreferenceController mController; - private TelephonyManager mTelephonyManagerFromSubId; - - @Mock - private PersistableBundle mPersistableBundle; @Before public void setUp() { MockitoAnnotations.initMocks(this); - final Context context = spy(ApplicationProvider.getApplicationContext()); - final int subId = SubscriptionManager.getDefaultVoiceSubscriptionId(); - final String rttSettingsPackageName = - context.getString(R.string.config_rtt_setting_package_name); - final CarrierConfigManager configManager = spy(new CarrierConfigManager(context)); - final TelephonyManager telephonyManager = spy(new TelephonyManager(context)); - final TelecomManager telecomManager = spy(new TelecomManager(context)); - mTelephonyManagerFromSubId = spy(new TelephonyManager(context, subId)); - doReturn(telephonyManager).when(context).getSystemService(TelephonyManager.class); - doReturn(mTelephonyManagerFromSubId).when(telephonyManager).createForSubscriptionId(subId); - doReturn(telecomManager).when(context).getSystemService(TelecomManager.class); - doReturn(configManager).when(context).getSystemService(CarrierConfigManager.class); - doReturn(mPersistableBundle).when(configManager).getConfigForSubId(subId); - doReturn(rttSettingsPackageName).when(telecomManager).getDefaultDialerPackage(); - mShadowPackageManager = shadowOf(context.getPackageManager()); mController = spy(new RTTSettingPreferenceController(context, "rtt_setting")); mController.mRTTIntent = new Intent("com.android.test.action.example"); } @Test - public void getStatus_carrierAndRttSupported_settingsIntent_available() { - doReturn(true).when(mTelephonyManagerFromSubId).isRttSupported(); - doReturn(true).when(mPersistableBundle).getBoolean( - CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL); - setupTestIntent(); - - assertThat(mController.getAvailabilityStatus()) - .isEqualTo(BasePreferenceController.AVAILABLE); - } - - @Test - public void getStatus_rttSupported_settingsIntent_unsupported() { - doReturn(true).when(mTelephonyManagerFromSubId).isRttSupported(); - doReturn(false).when(mPersistableBundle).getBoolean( - CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL); - setupTestIntent(); + public void getAvailabilityStatus_resolvedIsEmpty_shouldReturnUNSUPPORTED_ON_DEVICE() { + doReturn(true).when(mController).isRttSettingSupported(); assertThat(mController.getAvailabilityStatus()) .isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE); } @Test - public void getStatus_settingsIntent_unsupported() { - doReturn(false).when(mTelephonyManagerFromSubId).isRttSupported(); + public void getAvailabilityStatus_intentIsHandledButRttSettingNotSupported_returnAVAILABLE() { setupTestIntent(); + doReturn(false).when(mController).isRttSettingSupported(); - assertThat(mController.getAvailabilityStatus()).isEqualTo( - BasePreferenceController.UNSUPPORTED_ON_DEVICE); + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE); } @Test - public void getStatus_unsupported() { - doReturn(false).when(mTelephonyManagerFromSubId).isRttSupported(); + public void getAvailabilityStatus_intentCanBeHandledAndRttSettingSupported_returnAVAILABLE() { + setupTestIntent(); + doReturn(true).when(mController).isRttSettingSupported(); - assertThat(mController.getAvailabilityStatus()).isEqualTo( - BasePreferenceController.UNSUPPORTED_ON_DEVICE); + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(BasePreferenceController.AVAILABLE); } private void setupTestIntent() { diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAutofillPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAutofillPreferenceControllerTest.java index 26ec1c62d03..4d81069fbab 100644 --- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAutofillPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAutofillPreferenceControllerTest.java @@ -89,7 +89,7 @@ public class DefaultAutofillPreferenceControllerTest { final Preference pref = mock(Preference.class); mController.updateState(pref); - verify(pref).setSummary(R.string.app_list_preference_none); + verify(pref).setTitle(R.string.app_list_preference_none); } @Test diff --git a/tests/robotests/src/com/android/settings/development/qstile/WinscopeTraceTest.java b/tests/robotests/src/com/android/settings/development/qstile/WinscopeTraceTest.java index 52ba7a7f696..b4dab0d7cbd 100644 --- a/tests/robotests/src/com/android/settings/development/qstile/WinscopeTraceTest.java +++ b/tests/robotests/src/com/android/settings/development/qstile/WinscopeTraceTest.java @@ -24,10 +24,8 @@ import static com.android.settings.development.qstile.DevelopmentTiles.WinscopeT import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.spy; @@ -39,7 +37,6 @@ import android.os.RemoteException; import android.view.IWindowManager; import android.widget.Toast; -import com.android.internal.inputmethod.IBooleanResultCallback; import com.android.internal.view.IInputMethodManager; import com.android.settings.testutils.shadow.ShadowParcel; @@ -71,10 +68,6 @@ public class WinscopeTraceTest { public void setUp() { MockitoAnnotations.initMocks(this); mWinscopeTrace = spy(new DevelopmentTiles.WinscopeTrace()); - // default ImeTraceEnabled value, prevent tests from actually calling into IMM and - // await the result forever. - doReturn(false).when(mWinscopeTrace).isImeTraceEnabled(); - doNothing().when(mWinscopeTrace).setImeTraceEnabled(anyBoolean()); ReflectionHelpers.setField(mWinscopeTrace, "mWindowManager", mWindowManager); ReflectionHelpers.setField(mWinscopeTrace, "mInputMethodManager", mInputMethodManager); ReflectionHelpers.setField(mWinscopeTrace, "mSurfaceFlinger", mSurfaceFlinger); @@ -100,6 +93,7 @@ public class WinscopeTraceTest { public void sfReturnsTraceEnabled_shouldReturnEnabled() throws RemoteException { // Assume Window Trace and Input Method Manager are disabled. doReturn(false).when(mWindowManager).isWindowTraceEnabled(); + doReturn(false).when(mInputMethodManager).isImeTraceEnabled(); ShadowParcel.sReadBoolResult = true; assertThat(mWinscopeTrace.isEnabled()).isTrue(); verify(mSurfaceFlinger) @@ -120,6 +114,7 @@ public class WinscopeTraceTest { public void wmAndSfAndImmReturnTraceDisabled_shouldReturnDisabled() throws RemoteException { ShadowParcel.sReadBoolResult = false; doReturn(false).when(mWindowManager).isWindowTraceEnabled(); + doReturn(false).when(mInputMethodManager).isImeTraceEnabled(); assertThat(mWinscopeTrace.isEnabled()).isFalse(); verify(mSurfaceFlinger) .transact(eq(SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE), any(), any(), @@ -132,7 +127,7 @@ public class WinscopeTraceTest { throws RemoteException { ShadowParcel.sReadBoolResult = false; doReturn(false).when(mWindowManager).isWindowTraceEnabled(); - doReturn(true).when(mWinscopeTrace).isImeTraceEnabled(); + doReturn(true).when(mInputMethodManager).isImeTraceEnabled(); assertThat(mWinscopeTrace.isEnabled()).isTrue(); verify(mSurfaceFlinger) .transact(eq(SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE), any(), any(), @@ -145,7 +140,7 @@ public class WinscopeTraceTest { public void immReturnsTraceEnabled_shouldReturnEnabled() throws RemoteException { // Assume Window Manager and Surface Trace are disabled. ShadowParcel.sReadBoolResult = false; - doReturn(true).when(mWinscopeTrace).isImeTraceEnabled(); + doReturn(true).when(mInputMethodManager).isImeTraceEnabled(); assertThat(mWinscopeTrace.isEnabled()).isTrue(); } @@ -154,6 +149,7 @@ public class WinscopeTraceTest { public void immReturnsTraceDisabled_shouldReturnDisabled() throws RemoteException { // Assume Window Manager and Surface Trace are disabled. ShadowParcel.sReadBoolResult = false; + doReturn(false).when(mInputMethodManager).isImeTraceEnabled(); assertThat(mWinscopeTrace.isEnabled()).isFalse(); } @@ -171,6 +167,7 @@ public class WinscopeTraceTest { public void sfUnavailableAndWmAndImmReturnTraceDisabled_shouldReturnDisabled() throws RemoteException { doReturn(false).when(mWindowManager).isWindowTraceEnabled(); + doReturn(false).when(mInputMethodManager).isImeTraceEnabled(); ReflectionHelpers.setField(mWinscopeTrace, "mSurfaceFlinger", null); assertThat(mWinscopeTrace.isEnabled()).isFalse(); } @@ -185,7 +182,7 @@ public class WinscopeTraceTest { @Test public void setIsEnableTrue_shouldEnableImeTrace() throws RemoteException { mWinscopeTrace.setIsEnabled(true); - verify(mWinscopeTrace).setImeTraceEnabled(eq(true)); + verify(mInputMethodManager).startImeTrace(); verifyNoMoreInteractions(mInputMethodManager); } @@ -213,7 +210,7 @@ public class WinscopeTraceTest { @Config(shadows = ShadowParcel.class) public void setIsEnableFalse_shouldDisableImeTrace() throws RemoteException { mWinscopeTrace.setIsEnabled(false); - verify(mWinscopeTrace).setImeTraceEnabled(eq(false)); + verify(mInputMethodManager).stopImeTrace(); verifyNoMoreInteractions(mInputMethodManager); verify(mToast).show(); } @@ -254,8 +251,7 @@ public class WinscopeTraceTest { @Test public void setIsEnableAndImmThrowsRemoteException_shouldFailGracefully() throws RemoteException { - doThrow(new RemoteException("Unknown")).when(mInputMethodManager) - .isImeTraceEnabled(any(IBooleanResultCallback.Stub.class)); + doThrow(new RemoteException("Unknown")).when(mInputMethodManager).isImeTraceEnabled(); mWinscopeTrace.setIsEnabled(true); } diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java index 3eab600d841..5fcb9c1e8ef 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java @@ -54,7 +54,6 @@ import com.android.settings.applications.manageapplications.ManageApplications; import com.android.settings.dashboard.profileselector.ProfileSelectFragment; import com.android.settings.deviceinfo.StorageItemPreference; import com.android.settings.testutils.shadow.ShadowUserManager; -import com.android.settingslib.applications.StorageStatsSource; import com.android.settingslib.deviceinfo.StorageVolumeProvider; import org.junit.Before; @@ -340,12 +339,6 @@ public class StorageItemPreferenceControllerTest { result.documentsAndOtherSize = MEGABYTE_IN_BYTES * 50; result.trashSize = KILOBYTE_IN_BYTES * 100; result.allAppsExceptGamesSize = MEGABYTE_IN_BYTES * 90; - result.externalStats = - new StorageStatsSource.ExternalStorageStats( - MEGABYTE_IN_BYTES * 500, // total - MEGABYTE_IN_BYTES * 100, // audio - MEGABYTE_IN_BYTES * 150, // video - MEGABYTE_IN_BYTES * 200, 0); // image final SparseArray results = new SparseArray<>(); results.put(0, result); diff --git a/tests/robotests/src/com/android/settings/gestures/PreventRingingParentPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/PreventRingingParentPreferenceControllerTest.java index 4844a1cb0a7..48a047f2da8 100644 --- a/tests/robotests/src/com/android/settings/gestures/PreventRingingParentPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/gestures/PreventRingingParentPreferenceControllerTest.java @@ -22,6 +22,8 @@ import static android.provider.Settings.Secure.VOLUME_HUSH_OFF; import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE; import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import static com.google.common.truth.Truth.assertThat; @@ -33,8 +35,10 @@ import android.content.res.Resources; import android.provider.Settings; import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.widget.PrimarySwitchPreference; import org.junit.Before; import org.junit.Test; @@ -50,6 +54,9 @@ public class PreventRingingParentPreferenceControllerTest { @Mock private Resources mResources; + @Mock + PreferenceScreen mScreen; + private Context mContext; private PreventRingingParentPreferenceController mController; private Preference mPreference; @@ -58,21 +65,53 @@ public class PreventRingingParentPreferenceControllerTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application.getApplicationContext()); + when(mContext.getResources()).thenReturn(mResources); + when(mResources.getInteger( + com.android.internal.R.integer.config_keyChordPowerVolumeUp)).thenReturn( + PreventRingingParentPreferenceController.KEY_CHORD_POWER_VOLUME_UP_MUTE_TOGGLE); mController = new PreventRingingParentPreferenceController(mContext, "test_key"); - mPreference = new Preference(mContext); + mPreference = new PrimarySwitchPreference(mContext); + when(mScreen.findPreference("test_key")).thenReturn(mPreference); + mController.displayPreference(mScreen); } @Test - public void testIsAvailable_configIsTrue_shouldAvailableUnSearchable() { - when(mContext.getResources()).thenReturn(mResources); + public void isAvailable_configIsTrueAndKeyChordMute_shouldAvailableUnSearchable() { when(mResources.getBoolean( com.android.internal.R.bool.config_volumeHushGestureEnabled)).thenReturn(true); - assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @Test - public void testIsAvailable_configIsFalse_shouldReturnFalse() { + public void getAvailabilityStatus_configIsTrueAndKeyNotMute_shouldReturnDisabledDependent() { + when(mContext.getResources()).thenReturn(mResources); + when(mResources.getBoolean( + com.android.internal.R.bool.config_volumeHushGestureEnabled)).thenReturn(true); + when(mResources.getBoolean( + com.android.internal.R.bool.config_longPressOnPowerForAssistantSettingAvailable)) + .thenReturn(true); + when(mResources.getInteger( + com.android.internal.R.integer.config_keyChordPowerVolumeUp)).thenReturn(2); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + } + + @Test + public void getAvailabilityStatus_configIsTrueLppDisabled_shouldReturnUnsupportedOnDevice() { + when(mContext.getResources()).thenReturn(mResources); + when(mResources.getBoolean( + com.android.internal.R.bool.config_volumeHushGestureEnabled)).thenReturn(true); + when(mResources.getBoolean( + com.android.internal.R.bool.config_longPressOnPowerForAssistantSettingAvailable)) + .thenReturn(false); + when(mResources.getInteger( + com.android.internal.R.integer.config_keyChordPowerVolumeUp)).thenReturn(2); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + @Test + public void isAvailable_configIsFalse_shouldReturnFalse() { when(mContext.getResources()).thenReturn(mResources); when(mResources.getBoolean( com.android.internal.R.bool.config_volumeHushGestureEnabled)).thenReturn(false); @@ -101,6 +140,21 @@ public class PreventRingingParentPreferenceControllerTest { R.string.switch_off_text)); } + @Test + public void updateState_keyChordDisabled_summaryUpdated() { + when(mResources.getInteger( + com.android.internal.R.integer.config_keyChordPowerVolumeUp)).thenReturn(2); + // Ensure that the state displays unchecked even if the underlying field is set. + Settings.Secure.putInt(mContext.getContentResolver(), VOLUME_HUSH_GESTURE, + VOLUME_HUSH_MUTE); + mController.updateState(mPreference); + + assertThat(mPreference.isEnabled()).isFalse(); + assertThat(mPreference.getSummary()).isEqualTo(mContext.getResources().getText( + R.string.prevent_ringing_option_unavailable_lpp_summary)); + assertThat(mController.isChecked()).isFalse(); + } + @Test public void isChecked_vibrate_shouldReturnTrue() { Settings.Secure.putInt(mContext.getContentResolver(), VOLUME_HUSH_GESTURE, diff --git a/tests/robotests/src/com/android/settings/widget/SettingsMainSwitchPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/SettingsMainSwitchPreferenceTest.java index 31d10d925ad..c079029ffe0 100644 --- a/tests/robotests/src/com/android/settings/widget/SettingsMainSwitchPreferenceTest.java +++ b/tests/robotests/src/com/android/settings/widget/SettingsMainSwitchPreferenceTest.java @@ -76,6 +76,7 @@ public class SettingsMainSwitchPreferenceTest { mPreference.onBindViewHolder(mHolder); assertThat(mPreference.isShowing()).isTrue(); + assertThat(mPreference.isVisible()).isTrue(); } @Test @@ -85,5 +86,6 @@ public class SettingsMainSwitchPreferenceTest { mPreference.onBindViewHolder(mHolder); assertThat(mPreference.isShowing()).isFalse(); + assertThat(mPreference.isVisible()).isFalse(); } } diff --git a/tests/unit/src/com/android/settings/applications/autofill/PasswordsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/autofill/PasswordsPreferenceControllerTest.java index 25d989385d3..da860ecb539 100644 --- a/tests/unit/src/com/android/settings/applications/autofill/PasswordsPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/applications/autofill/PasswordsPreferenceControllerTest.java @@ -21,11 +21,19 @@ import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_U import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.os.Looper; +import android.os.UserHandle; import android.service.autofill.AutofillServiceInfo; import androidx.lifecycle.Lifecycle; @@ -40,9 +48,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.collect.Lists; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import java.util.Collections; import java.util.List; @@ -56,7 +64,7 @@ public class PasswordsPreferenceControllerTest { @Before public void setUp() { - mContext = ApplicationProvider.getApplicationContext(); + mContext = spy(ApplicationProvider.getApplicationContext()); if (Looper.myLooper() == null) { Looper.prepare(); // needed to create the preference screen } @@ -66,6 +74,15 @@ public class PasswordsPreferenceControllerTest { mScreen.addPreference(mPasswordsPreferenceCategory); } + @Test + // Tests that getAvailabilityStatus() does not throw an exception if it's called before the + // Controller is initialized (this can happen during indexing). + public void getAvailabilityStatus_withoutInit_returnsUnavailable() { + PasswordsPreferenceController controller = + new PasswordsPreferenceController(mContext, mPasswordsPreferenceCategory.getKey()); + assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + @Test public void getAvailabilityStatus_noServices_returnsUnavailable() { PasswordsPreferenceController controller = @@ -105,21 +122,26 @@ public class PasswordsPreferenceControllerTest { assertThat(mPasswordsPreferenceCategory.getPreferenceCount()).isEqualTo(0); } - @Ignore("TODO: Fix the test to handle the service binding.") @Test @UiThreadTest public void displayPreference_withPasswords_addsPreference() { AutofillServiceInfo service = createServiceWithPasswords(); + service.getServiceInfo().packageName = ""; + service.getServiceInfo().name = ""; PasswordsPreferenceController controller = createControllerWithServices(Lists.newArrayList(service)); - controller.onCreate(() -> mock(Lifecycle.class)); + doReturn(false).when(mContext).bindServiceAsUser(any(), any(), anyInt(), any()); controller.displayPreference(mScreen); assertThat(mPasswordsPreferenceCategory.getPreferenceCount()).isEqualTo(1); Preference pref = mPasswordsPreferenceCategory.getPreference(0); assertThat(pref.getIcon()).isNotNull(); - assertThat(pref.getIntent().getComponent()) + pref.performClick(); + ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); + UserHandle user = mContext.getUser(); + verify(mContext).startActivityAsUser(intentCaptor.capture(), eq(user)); + assertThat(intentCaptor.getValue().getComponent()) .isEqualTo( new ComponentName( service.getServiceInfo().packageName, @@ -128,8 +150,10 @@ public class PasswordsPreferenceControllerTest { private PasswordsPreferenceController createControllerWithServices( List availableServices) { - return new PasswordsPreferenceController( - mContext, mPasswordsPreferenceCategory.getKey(), availableServices); + PasswordsPreferenceController controller = + new PasswordsPreferenceController(mContext, mPasswordsPreferenceCategory.getKey()); + controller.init(() -> mock(Lifecycle.class), availableServices); + return controller; } private AutofillServiceInfo createServiceWithPasswords() { diff --git a/tests/unit/src/com/android/settings/search/CustomSiteMapRegistryTest.java b/tests/unit/src/com/android/settings/search/CustomSiteMapRegistryTest.java index 3848fe446b0..5eb3b336ede 100644 --- a/tests/unit/src/com/android/settings/search/CustomSiteMapRegistryTest.java +++ b/tests/unit/src/com/android/settings/search/CustomSiteMapRegistryTest.java @@ -62,7 +62,7 @@ public class CustomSiteMapRegistryTest { } @Test - public void shouldContainRecentLocationRequestSeeAllFragmentPairs() { + public void shouldContainRecentLocationAccessSeeAllFragmentPairs() { assertThat(CustomSiteMapRegistry.CUSTOM_SITE_MAP.get( RecentLocationAccessSeeAllFragment.class.getName())).isEqualTo( LocationSettings.class.getName());