Snap for 10106040 from b8e02ef73f to udc-release

Change-Id: Ifef13bcf927e29821a12ee4b500e1f885d5026c8
This commit is contained in:
Android Build Coastguard Worker
2023-05-10 23:29:19 +00:00
35 changed files with 573 additions and 493 deletions

View File

@@ -4868,22 +4868,6 @@
</intent-filter>
</receiver>
<activity
android:name=".notetask.shortcut.CreateNoteTaskShortcutActivity"
android:enabled="false"
android:exported="true"
android:excludeFromRecents="true"
android:resizeableActivity="false"
android:theme="@android:style/Theme.NoDisplay"
android:label="@string/note_task_shortcut_label"
android:icon="@drawable/ic_note_task_shortcut_widget">
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="com.android.settings.bluetooth.QrCodeScanModeActivity"
android:permission="android.permission.BLUETOOTH_CONNECT"

View File

@@ -15,7 +15,7 @@ message BatteryOptimizeHistoricalLogEntry {
// The action to set optimize mode
enum Action {
UNKNOWN = 0;
MANUAL = 1;
LEAVE = 1;
APPLY = 2;
RESET = 3;
RESTORE = 4;
@@ -24,4 +24,5 @@ message BatteryOptimizeHistoricalLogEntry {
optional string package_name = 1;
optional Action action = 2;
optional string action_description = 3;
optional int64 timestamp = 4;
}

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="48"
android:viewportHeight="48">
<group>
<path
android:fillColor="#0B57D0"
android:pathData="M48 24C48 10.7452 37.2548 0 24 0C10.7452 0 0 10.7452 0 24C0 37.2548 10.7452 48 24 48C37.2548 48 48 37.2548 48 24Z" />
<path
android:fillColor="#ffffff"
android:pathData="M37.692 16.8L36 15.108C35.556 14.652 34.944 14.4 34.308 14.4C33.672 14.4 33.06 14.652 32.616 15.108L23.268 24.456L20.508 27.216L19.248 32.28C19.212 32.352 19.2 32.448 19.2 32.532C19.2 33.12 19.68 33.6 20.268 33.6C20.352 33.6 20.448 33.588 20.532 33.564L25.596 32.304L28.356 29.544L37.704 20.196C38.148 19.74 38.4 19.128 38.4 18.492C38.4 17.856 38.148 17.244 37.692 16.8ZM26.652 27.852L25.452 29.052L23.76 27.36L24.96 26.16L34.308 16.8L36 18.492L26.652 27.852Z" />
<path
android:fillColor="#ffffff"
android:pathData="M17.825 33.6C12.257 33.6 10.2 31.9581 10.2 28.7351C10.2 25.8284 12.727 24.4472 16.656 23.8703C17.95 23.6802 18.6125 23.137 18.6125 22.5654C18.6125 20.9818 15.415 21.0788 14.4 21.0324V18.6C14.4 18.6 17.95 18.6 19.65 19.8923C20.5181 20.5521 21 21.4125 21 22.7149C21 24.5027 19.7375 25.9099 16.656 26.1633C14.6206 26.3307 12.6 26.9351 12.6 28.7351C12.6 30.3527 14.616 31.1676 18.6 31.1676L17.825 33.6Z" />
</group>
</vector>

View File

@@ -991,6 +991,8 @@
<string name="setup_fingerprint_enroll_enrolling_skip_title">Skip fingerprint setup?</string>
<!-- Content of the dialog shown when the user tries to skip fingerprint setup, asking them to confirm the action [CHAR LIMIT=NONE] -->
<string name="setup_fingerprint_enroll_enrolling_skip_message">You\u2019ve chosen to use your fingerprint as one way to unlock your phone. If you skip now, you\u2019ll need to set this up later. Setup takes only a minute or so.</string>
<!-- Title of dialog shown when the user tries to skip for setup screen lock, warning them of potential consequences of not doing so [CHAR LIMIT=48]-->
<string name="lock_screen_skip_setup_title">Skip setup for <xliff:g id="options" example="PIN • Face • Fingerprint">%s</xliff:g>?</string>
<!-- Title of dialog shown when the user tries to skip setting up a PIN, warning them of potential consequences of not doing so [CHAR LIMIT=48]-->
<string name="lock_screen_pin_skip_title">Skip PIN setup?</string>
<!-- Title of dialog shown when the user tries to skip setting up a PIN, warning them of potential consequences of not doing so [CHAR LIMIT=90]-->
@@ -1088,7 +1090,7 @@
<!-- Action label for the issue card in Safety Center when no screen lock is set [CHAR LIMIT=50] -->
<string name="no_screen_lock_issue_action_label">Set screen lock</string>
<!-- Title of the notification shown by Safety Center when no screen lock is set. This notification is shown in the notification shade, outside of the main Safety Center UI. [CHAR LIMIT=50] -->
<string name="no_screen_lock_issue_notification_title">Device has no screen lock</string>
<string name="no_screen_lock_issue_notification_title">Set a screen lock</string>
<!-- Summary/body text of the notification shown by Safety Center when no screen lock is set. This notification is shown in the notification shade, outside of the main Safety Center UI. [CHAR LIMIT=NONE] -->
<string name="no_screen_lock_issue_notification_text">For added security, set a PIN, pattern, or password for this device.</string>
@@ -2275,6 +2277,8 @@
<string name="accessibility_category_work">Work profile accounts - <xliff:g id="managed_by" example="Managed by Corporate application">%s</xliff:g></string>
<!-- Content description for personal profile accounts group [CHAR LIMIT=NONE] -->
<string name="accessibility_category_personal">Personal profile accounts</string>
<!-- Content description for personal clone accounts group [CHAR LIMIT=NONE] -->
<string name="accessibility_category_clone">Clone profile accounts</string>
<!-- Content description for work profile details page title [CHAR LIMIT=NONE] -->
<string name="accessibility_work_account_title">Work account - <xliff:g id="managed_by" example="Email provider">%s</xliff:g></string>
<!-- Content description for personal profile details page title [CHAR LIMIT=NONE] -->
@@ -12086,7 +12090,4 @@
<!-- Warning message when we try to dock an app not supporting multiple instances split into multiple sides [CHAR LIMIT=NONE] -->
<string name="dock_multi_instances_not_supported_text">"This app can only be opened in 1 window"</string>
<!-- [CHAR LIMIT=30] Label used to open Note Task -->
<string name="note_task_shortcut_label">Note shortcut</string>
</resources>

View File

@@ -16,8 +16,10 @@
package com.android.settings.accounts;
import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_CLONE;
import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_PERSONAL;
import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_WORK;
import static android.app.admin.DevicePolicyResources.Strings.Settings.CLONE_CATEGORY_HEADER;
import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_BY;
import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_PROFILE_SETTINGS_TITLE;
import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER;
@@ -349,28 +351,34 @@ public class AccountPreferenceController extends AbstractPreferenceController
preferenceGroup.setContentDescription(title);
} else if (userInfo.isManagedProfile()) {
if (mType == ProfileSelectFragment.ProfileType.ALL) {
preferenceGroup.setTitle(
mDpm.getResources().getString(WORK_CATEGORY_HEADER,
() -> mContext.getString(R.string.category_work)));
setCategoryTitleFromDevicePolicyResource(preferenceGroup, WORK_CATEGORY_HEADER,
R.string.category_work);
final String workGroupSummary = getWorkGroupSummary(context, userInfo);
preferenceGroup.setSummary(workGroupSummary);
preferenceGroup.setContentDescription(
mDpm.getResources().getString(ACCESSIBILITY_CATEGORY_WORK, () ->
mContext.getString(
R.string.accessibility_category_work, workGroupSummary)));
setContentDescriptionFromDevicePolicyResource(preferenceGroup,
ACCESSIBILITY_CATEGORY_WORK, R.string.accessibility_category_work,
workGroupSummary);
}
profileData.removeWorkProfilePreference = newRemoveWorkProfilePreference();
mHelper.enforceRestrictionOnPreference(profileData.removeWorkProfilePreference,
DISALLOW_REMOVE_MANAGED_PROFILE, UserHandle.myUserId());
profileData.managedProfilePreference = newManagedProfileSettings();
} else {
} else if (userInfo.isCloneProfile()) {
if (mType == ProfileSelectFragment.ProfileType.ALL) {
preferenceGroup.setTitle(
mDpm.getResources().getString(PERSONAL_CATEGORY_HEADER,
() -> mContext.getString(R.string.category_personal)));
preferenceGroup.setContentDescription(
mDpm.getResources().getString(ACCESSIBILITY_CATEGORY_PERSONAL, () ->
mContext.getString(R.string.accessibility_category_personal)));
setCategoryTitleFromDevicePolicyResource(preferenceGroup, CLONE_CATEGORY_HEADER,
R.string.category_clone);
setContentDescriptionFromDevicePolicyResource(preferenceGroup,
ACCESSIBILITY_CATEGORY_CLONE, R.string.accessibility_category_clone,
null);
}
} else {
// Primary Profile
if (mType == ProfileSelectFragment.ProfileType.ALL) {
setCategoryTitleFromDevicePolicyResource(preferenceGroup, PERSONAL_CATEGORY_HEADER,
R.string.category_personal);
setContentDescriptionFromDevicePolicyResource(preferenceGroup,
ACCESSIBILITY_CATEGORY_PERSONAL, R.string.accessibility_category_personal,
null);
}
}
final PreferenceScreen screen = mFragment.getPreferenceScreen();
@@ -381,13 +389,33 @@ public class AccountPreferenceController extends AbstractPreferenceController
if (userInfo.isEnabled()) {
profileData.authenticatorHelper = new AuthenticatorHelper(context,
userInfo.getUserHandle(), this);
profileData.addAccountPreference = newAddAccountPreference();
mHelper.enforceRestrictionOnPreference(profileData.addAccountPreference,
DISALLOW_MODIFY_ACCOUNTS, userInfo.id);
if (!userInfo.isCloneProfile()) {
profileData.addAccountPreference = newAddAccountPreference();
mHelper.enforceRestrictionOnPreference(profileData.addAccountPreference,
DISALLOW_MODIFY_ACCOUNTS, userInfo.id);
}
}
mProfiles.put(userInfo.id, profileData);
}
private void setCategoryTitleFromDevicePolicyResource(
AccessiblePreferenceCategory preferenceGroup, String stringId, int resourceIdentifier) {
preferenceGroup.setTitle(
mDpm.getResources().getString(stringId,
() -> mContext.getString(resourceIdentifier)));
}
private void setContentDescriptionFromDevicePolicyResource(
AccessiblePreferenceCategory preferenceGroup, String stringId, int resourceIdentifier,
String formatArgs) {
preferenceGroup.setContentDescription(mDpm.getResources().getString(stringId, () -> {
if (formatArgs != null) {
return mContext.getString(resourceIdentifier, formatArgs);
}
return mContext.getString(resourceIdentifier);
}));
}
private RestrictedPreference newAddAccountPreference() {
RestrictedPreference preference =
new RestrictedPreference(mFragment.getPreferenceManager().getContext());

View File

@@ -620,6 +620,9 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
completeEnableProviderDialogBox(
whichButton, packageName, setActivityResult);
}
@Override
public void onCancel() {}
};
return new NewProviderConfirmationDialogFragment(host, packageName, appName);
@@ -666,6 +669,9 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
new DialogHost() {
@Override
public void onDialogClick(int whichButton) {}
@Override
public void onCancel() {}
};
return new ErrorDialogFragment(host);
@@ -689,6 +695,12 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
pref.setChecked(true);
}
}
@Override
public void onCancel() {
// If we dismiss the dialog then re-enable.
pref.setChecked(true);
}
};
return new ConfirmationDialogFragment(host, packageName, appName);
@@ -705,6 +717,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
/** Called when the dialog button is clicked. */
private static interface DialogHost {
void onDialogClick(int whichButton);
void onCancel();
}
/** Called to send messages back to the parent fragment. */
@@ -754,6 +768,11 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
public DialogHost getDialogHost() {
return mDialogHost;
}
@Override
public void onCancel(@NonNull DialogInterface dialog) {
getDialogHost().onCancel();
}
}
/** Dialog showing error when too many providers are selected. */

View File

@@ -156,7 +156,7 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
// If there are multiple autofill services then pick the first one.
if (mKey.startsWith(serviceInfo.packageName)) {
if (mKey != null && mKey.startsWith(serviceInfo.packageName)) {
final String settingsActivity;
try {
settingsActivity =

View File

@@ -28,6 +28,8 @@ import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.os.Bundle;
import android.os.storage.StorageManager;
import android.text.BidiFormatter;
import android.text.SpannableStringBuilder;
import android.util.FeatureFlagUtils;
import android.util.Log;
import android.view.Surface;
@@ -38,6 +40,7 @@ import androidx.fragment.app.FragmentActivity;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.settings.R;
import com.android.settings.SetupWizardUtils;
import com.android.settings.biometrics.face.FaceEnrollIntroduction;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
@@ -45,6 +48,7 @@ import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollFindSensor;
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollIntroduction;
import com.android.settings.biometrics2.ui.view.FingerprintEnrollmentActivity;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockGeneric;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.password.SetupChooseLockGeneric;
@@ -60,6 +64,9 @@ import java.lang.annotation.RetentionPolicy;
public class BiometricUtils {
private static final String TAG = "BiometricUtils";
/** The character ' • ' to separate the setup choose options */
public static final String SEPARATOR = " \u2022 ";
// Note: Theis IntDef must align SystemUI DevicePostureInt
@IntDef(prefix = {"DEVICE_POSTURE_"}, value = {
DEVICE_POSTURE_UNKNOWN,
@@ -496,4 +503,45 @@ public class BiometricUtils {
public static boolean isLandscape(@NonNull Context context) {
return context.getDisplay().getRotation() == Surface.ROTATION_90;
}
/**
* Returns true if the device supports Face enrollment in SUW flow
*/
public static boolean isFaceSupportedInSuw(Context context) {
return FeatureFactory.getFactory(context).getFaceFeatureProvider().isSetupWizardSupported(
context);
}
/**
* Returns the combined screen lock options by device biometrics config
* @param context the application context
* @param screenLock the type of screen lock(PIN, Pattern, Password) in string
* @param hasFingerprint device support fingerprint or not
* @param isFaceSupported device support face or not
* @return the options combined with screen lock, face, and fingerprint in String format.
*/
public static String getCombinedScreenLockOptions(Context context,
CharSequence screenLock, boolean hasFingerprint, boolean isFaceSupported) {
final SpannableStringBuilder ssb = new SpannableStringBuilder();
final BidiFormatter bidi = BidiFormatter.getInstance();
// Assume the flow is "Screen Lock" + "Face" + "Fingerprint"
ssb.append(bidi.unicodeWrap(screenLock));
if (isFaceSupported) {
ssb.append(bidi.unicodeWrap(SEPARATOR));
ssb.append(bidi.unicodeWrap(
capitalize(context.getString(R.string.keywords_face_settings))));
}
if (hasFingerprint) {
ssb.append(bidi.unicodeWrap(SEPARATOR));
ssb.append(bidi.unicodeWrap(
capitalize(context.getString(R.string.security_settings_fingerprint))));
}
return ssb.toString();
}
private static String capitalize(final String input) {
return Character.toUpperCase(input.charAt(0)) + input.substring(1);
}
}

View File

@@ -165,11 +165,7 @@ public class DataUsageList extends DataUsageBaseFragment
}
processArgument();
mMobileNetworkRepository = MobileNetworkRepository.getInstance(getContext());
ThreadUtils.postOnBackgroundThread(() -> {
mSubscriptionInfoEntity = mMobileNetworkRepository.getSubInfoById(
String.valueOf(mSubId));
});
updateSubscriptionInfoEntity();
mDataStateListener = new MobileDataEnabledListener(activity, this);
}
@@ -294,6 +290,15 @@ public class DataUsageList extends DataUsageBaseFragment
}
}
@VisibleForTesting
void updateSubscriptionInfoEntity() {
mMobileNetworkRepository = MobileNetworkRepository.getInstance(getContext());
ThreadUtils.postOnBackgroundThread(() -> {
mSubscriptionInfoEntity = mMobileNetworkRepository.getSubInfoById(
String.valueOf(mSubId));
});
}
/**
* Implementation of {@code MobileDataEnabledListener.Client}
*/
@@ -503,11 +508,13 @@ public class DataUsageList extends DataUsageBaseFragment
Collections.sort(items);
final List<String> packageNames = Arrays.asList(getContext().getResources().getStringArray(
R.array.datausage_hiding_carrier_service_package_names));
// When there is no specified SubscriptionInfo, Wi-Fi data usage will be displayed.
// In this case, the carrier service package also needs to be hidden.
boolean shouldHidePackageName = mSubscriptionInfoEntity != null
? Arrays.stream(getContext().getResources().getIntArray(
R.array.datausage_hiding_carrier_service_carrier_id))
.anyMatch(carrierId -> (carrierId == mSubscriptionInfoEntity.carrierId))
: false;
: true;
for (int i = 0; i < items.size(); i++) {
UidDetail detail = mUidDetailProvider.getUidDetail(items.get(i).key, true);

View File

@@ -291,7 +291,7 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
BatteryHistoricalLogUtil.writeLog(
getContext().getApplicationContext(),
Action.MANUAL,
Action.LEAVE,
BatteryHistoricalLogUtil.getPackageNameWithUserId(
mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()),
mLogStringBuilder.toString());

View File

@@ -24,7 +24,6 @@ import android.app.backup.BackupHelper;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.os.Build;
import android.os.IDeviceIdleController;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -48,7 +47,6 @@ public final class BatteryBackupHelper implements BackupHelper {
/** An inditifier for {@link BackupHelper}. */
public static final String TAG = "BatteryBackupHelper";
private static final String DEVICE_IDLE_SERVICE = "deviceidle";
private static final boolean DEBUG = Build.TYPE.equals("userdebug");
static final String DELIMITER = ",";
static final String DELIMITER_MODE = ":";
@@ -119,7 +117,7 @@ public final class BatteryBackupHelper implements BackupHelper {
Log.e(TAG, "backupFullPowerList() failed", e);
return null;
}
// Ignores unexpected emptty result case.
// Ignores unexpected empty result case.
if (allowlistedApps == null || allowlistedApps.length == 0) {
Log.w(TAG, "no data found in the getFullPowerList()");
return new ArrayList<>();
@@ -145,8 +143,7 @@ public final class BatteryBackupHelper implements BackupHelper {
final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
// Converts application into the AppUsageState.
for (ApplicationInfo info : applications) {
final int mode = appOps.checkOpNoThrow(
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, info.uid, info.packageName);
final int mode = BatteryOptimizeUtils.getMode(appOps, info.uid, info.packageName);
@BatteryOptimizeUtils.OptimizationMode
final int optimizationMode = BatteryOptimizeUtils.getAppOptimizationMode(
mode, allowlistedApps.contains(info.packageName));
@@ -159,7 +156,7 @@ public final class BatteryBackupHelper implements BackupHelper {
final String packageOptimizeMode =
info.packageName + DELIMITER_MODE + optimizationMode;
builder.append(packageOptimizeMode + DELIMITER);
debugLog(packageOptimizeMode);
Log.d(TAG, "backupOptimizationMode: " + packageOptimizeMode);
backupCount++;
}
@@ -255,9 +252,8 @@ public final class BatteryBackupHelper implements BackupHelper {
}
private boolean isSystemOrDefaultApp(String packageName, int uid) {
final PowerAllowlistBackend powerAllowlistBackend = getPowerAllowlistBackend();
return powerAllowlistBackend.isSysAllowlisted(packageName)
|| powerAllowlistBackend.isDefaultActiveApp(packageName, uid);
return BatteryOptimizeUtils.isSystemOrDefaultApp(
getPowerAllowlistBackend(), packageName, uid);
}
private ArraySet<ApplicationInfo> getInstalledApplications() {
@@ -267,10 +263,6 @@ public final class BatteryBackupHelper implements BackupHelper {
return BatteryOptimizeUtils.getInstalledApplications(mContext, getIPackageManager());
}
private void debugLog(String debugContent) {
if (DEBUG) Log.d(TAG, debugContent);
}
private static void writeBackupData(
BackupDataOutput data, String dataKey, String dataContent) {
final byte[] dataContentBytes = dataContent.getBytes();
@@ -283,6 +275,6 @@ public final class BatteryBackupHelper implements BackupHelper {
}
private static boolean isOwner() {
return UserHandle.myUserId() == UserHandle.USER_OWNER;
return UserHandle.myUserId() == UserHandle.USER_SYSTEM;
}
}

View File

@@ -21,6 +21,7 @@ import android.content.SharedPreferences;
import android.util.Base64;
import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
import com.android.settings.fuelgauge.batteryusage.ConvertUtils;
import com.google.common.annotations.VisibleForTesting;
@@ -49,6 +50,7 @@ public final class BatteryHistoricalLogUtil {
.setPackageName(pkg)
.setAction(action)
.setActionDescription(actionDescription)
.setTimestamp(System.currentTimeMillis())
.build());
}
@@ -89,6 +91,7 @@ public final class BatteryHistoricalLogUtil {
if (logEntryList.isEmpty()) {
writer.println("\tNo past logs.");
} else {
writer.println("0:RESTRICTED 1:UNRESTRICTED 2:OPTIMIZED 3:UNKNOWN");
logEntryList.forEach(entry -> writer.println(toString(entry)));
}
}
@@ -101,8 +104,9 @@ public final class BatteryHistoricalLogUtil {
}
private static String toString(BatteryOptimizeHistoricalLogEntry entry) {
return String.format("%s\tAction:%s\tEvent:%s",
entry.getPackageName(), entry.getAction(), entry.getActionDescription());
return String.format("%s\tAction:%s\tEvent:%s\tTimestamp:%s", entry.getPackageName(),
entry.getAction(), entry.getActionDescription(),
ConvertUtils.utcToLocalTimeForLogging(entry.getTimestamp()));
}
@VisibleForTesting

View File

@@ -83,8 +83,7 @@ public class BatteryOptimizeUtils {
mAppOpsManager = context.getSystemService(AppOpsManager.class);
mBatteryUtils = BatteryUtils.getInstance(context);
mPowerAllowListBackend = PowerAllowlistBackend.getInstance(context);
mMode = mAppOpsManager
.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mPackageName);
mMode = getMode(mAppOpsManager, mUid, mPackageName);
mAllowListed = mPowerAllowListBackend.isAllowlisted(mPackageName, mUid);
}
@@ -204,7 +203,12 @@ public class BatteryOptimizeUtils {
return mPackageName == null ? UNKNOWN_PACKAGE : mPackageName;
}
private static boolean isSystemOrDefaultApp(
static int getMode(AppOpsManager appOpsManager, int uid, String packageName) {
return appOpsManager.checkOpNoThrow(
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName);
}
static boolean isSystemOrDefaultApp(
PowerAllowlistBackend powerAllowlistBackend, String packageName, int uid) {
return powerAllowlistBackend.isSysAllowlisted(packageName)
|| powerAllowlistBackend.isDefaultActiveApp(packageName, uid);

View File

@@ -67,9 +67,6 @@ public class BatteryTipLoader extends AsyncLoaderCompat<List<BatteryTip>> {
tips.add(new LowBatteryDetector(context, policy, batteryInfo, isPowerSaveMode).detect());
tips.add(new HighUsageDetector(context, policy, mBatteryUsageStats, batteryInfo).detect());
tips.add(new SmartBatteryDetector(
context, policy, batteryInfo, context.getContentResolver(), isPowerSaveMode)
.detect());
tips.add(new BatteryDefenderDetector(batteryInfo, context).detect());
tips.add(new DockDefenderDetector(batteryInfo, context).detect());
tips.add(new IncompatibleChargerDetector(context).detect());

View File

@@ -169,9 +169,11 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
private void mapLanguageWithLayout(InputMethodInfo info, InputMethodSubtype subtype) {
CharSequence subtypeLabel = getSubtypeLabel(mContext, info, subtype);
KeyboardLayout[] keyboardLayouts = getKeyboardLayouts(info, subtype);
String layout = getKeyboardLayout(info, subtype);
KeyboardLayout[] keyboardLayouts =
NewKeyboardSettingsUtils.getKeyboardLayouts(
mIm, mUserId, mInputDeviceIdentifier, info, subtype);
String layout = NewKeyboardSettingsUtils.getKeyboardLayout(
mIm, mUserId, mInputDeviceIdentifier, info, subtype);
if (layout != null) {
for (int i = 0; i < keyboardLayouts.length; i++) {
if (keyboardLayouts[i].getDescriptor().equals(layout)) {
@@ -220,7 +222,6 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
preference -> {
showKeyboardLayoutPicker(
keyboardInfo.getSubtypeLabel(),
keyboardInfo.getLayout(),
mInputDeviceIdentifier,
mUserId,
keyboardInfo.getInputMethodInfo(),
@@ -267,7 +268,6 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
private void showKeyboardLayoutPicker(
CharSequence subtypeLabel,
String layout,
InputDeviceIdentifier inputDeviceIdentifier,
int userId,
InputMethodInfo inputMethodInfo,
@@ -281,7 +281,6 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE, inputMethodSubtype);
arguments.putInt(NewKeyboardSettingsUtils.EXTRA_USER_ID, userId);
arguments.putCharSequence(NewKeyboardSettingsUtils.EXTRA_TITLE, subtypeLabel);
arguments.putString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_LAYOUT, layout);
new SubSettingLauncher(mContext)
.setSourceMetricsCategory(getMetricsCategory())
.setDestination(NewKeyboardLayoutPickerFragment.class.getName())
@@ -289,16 +288,6 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
.launch();
}
private KeyboardLayout[] getKeyboardLayouts(InputMethodInfo info, InputMethodSubtype subtype) {
return mIm.getKeyboardLayoutListForInputDevice(
mInputDeviceIdentifier, mUserId, info, subtype);
}
private String getKeyboardLayout(InputMethodInfo info, InputMethodSubtype subtype) {
return mIm.getKeyboardLayoutForInputDevice(
mInputDeviceIdentifier, mUserId, info, subtype);
}
private CharSequence getSubtypeLabel(
Context context, InputMethodInfo info, InputMethodSubtype subtype) {
return subtype.getDisplayName(

View File

@@ -20,6 +20,7 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.input.KeyboardLayout;
import android.os.Bundle;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
@@ -31,28 +32,50 @@ public class NewKeyboardLayoutPickerContent extends DashboardFragment {
private static final String TAG = "KeyboardLayoutPicker";
private InputManager mIm;
private int mUserId;
private InputDeviceIdentifier mIdentifier;
private InputMethodInfo mInputMethodInfo;
private InputMethodSubtype mInputMethodSubtype;
@Override
public void onAttach(Context context) {
super.onAttach(context);
InputManager inputManager = getContext().getSystemService(InputManager.class);
mIm = getContext().getSystemService(InputManager.class);
Bundle arguments = getArguments();
final CharSequence title = arguments.getCharSequence(NewKeyboardSettingsUtils.EXTRA_TITLE);
final String layout = arguments.getString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_LAYOUT);
final int userId = arguments.getInt(NewKeyboardSettingsUtils.EXTRA_USER_ID);
final InputDeviceIdentifier identifier =
mUserId = arguments.getInt(NewKeyboardSettingsUtils.EXTRA_USER_ID);
mIdentifier =
arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER);
final InputMethodInfo inputMethodInfo =
mInputMethodInfo =
arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_INFO);
final InputMethodSubtype inputMethodSubtype =
mInputMethodSubtype =
arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE);
if (identifier == null
|| NewKeyboardSettingsUtils.getInputDevice(inputManager, identifier) == null) {
if (mIdentifier == null
|| NewKeyboardSettingsUtils.getInputDevice(mIm, mIdentifier) == null) {
getActivity().finish();
return;
}
getActivity().setTitle(title);
use(NewKeyboardLayoutPickerController.class).initialize(this /*parent*/, userId,
identifier, inputMethodInfo, inputMethodSubtype, layout);
use(NewKeyboardLayoutPickerController.class).initialize(this /*parent*/, mUserId,
mIdentifier, mInputMethodInfo, mInputMethodSubtype, getSelectedLayoutLabel());
}
private String getSelectedLayoutLabel() {
String label = getContext().getString(R.string.keyboard_default_layout);
String layout = NewKeyboardSettingsUtils.getKeyboardLayout(
mIm, mUserId, mIdentifier, mInputMethodInfo, mInputMethodSubtype);
KeyboardLayout[] keyboardLayouts = NewKeyboardSettingsUtils.getKeyboardLayouts(
mIm, mUserId, mIdentifier, mInputMethodInfo, mInputMethodSubtype);
if (layout != null) {
for (int i = 0; i < keyboardLayouts.length; i++) {
if (keyboardLayouts[i].getDescriptor().equals(layout)) {
label = keyboardLayouts[i].getLabel();
break;
}
}
}
return label;
}
@Override

View File

@@ -19,6 +19,7 @@ package com.android.settings.inputmethod;
import android.content.Context;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.input.KeyboardLayout;
import android.view.InputDevice;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
@@ -39,7 +40,6 @@ public class NewKeyboardSettingsUtils {
"com.android.settings.inputmethod.EXTRA_INTENT_FROM";
static final String EXTRA_TITLE = "keyboard_layout_picker_title";
static final String EXTRA_KEYBOARD_LAYOUT = "keyboard_layout";
static final String EXTRA_USER_ID = "user_id";
static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier";
static final String EXTRA_INPUT_METHOD_INFO = "input_method_info";
@@ -117,4 +117,14 @@ public class NewKeyboardSettingsUtils {
static InputDevice getInputDevice(InputManager im, InputDeviceIdentifier identifier) {
return im.getInputDeviceByDescriptor(identifier.getDescriptor());
}
static KeyboardLayout[] getKeyboardLayouts(InputManager inputManager, int userId,
InputDeviceIdentifier identifier, InputMethodInfo info, InputMethodSubtype subtype) {
return inputManager.getKeyboardLayoutListForInputDevice(identifier, userId, info, subtype);
}
static String getKeyboardLayout(InputManager inputManager, int userId,
InputDeviceIdentifier identifier, InputMethodInfo info, InputMethodSubtype subtype) {
return inputManager.getKeyboardLayoutForInputDevice(identifier, userId, info, subtype);
}
}

View File

@@ -67,12 +67,14 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
private static final String SHOW_VIRTUAL_KEYBOARD_SWITCH = "show_virtual_keyboard_switch";
private static final String KEYBOARD_SHORTCUTS_HELPER = "keyboard_shortcuts_helper";
private static final String MODIFIER_KEYS_SETTINGS = "modifier_keys_settings";
private static final String EXTRA_AUTO_SELECTION = "auto_selection";
@NonNull
private final ArrayList<HardKeyboardDeviceInfo> mLastHardKeyboards = new ArrayList<>();
private InputManager mIm;
private InputMethodManager mImm;
private InputDeviceIdentifier mAutoInputDeviceIdentifier;
@NonNull
private PreferenceCategory mKeyboardAssistanceCategory;
@NonNull
@@ -84,6 +86,12 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
static final String EXTRA_BT_ADDRESS = "extra_bt_address";
private String mBluetoothAddress;
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putParcelable(EXTRA_AUTO_SELECTION, mAutoInputDeviceIdentifier);
super.onSaveInstanceState(outState);
}
@Override
public void onCreatePreferences(Bundle bundle, String s) {
Activity activity = Preconditions.checkNotNull(getActivity());
@@ -107,15 +115,19 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER);
// TODO (b/271391879): The EXTRA_INTENT_FROM is used for the future metrics.
if (inputDeviceIdentifier != null) {
Bundle arguments = new Bundle();
arguments.putParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER,
inputDeviceIdentifier);
new SubSettingLauncher(getContext())
.setSourceMetricsCategory(getMetricsCategory())
.setDestination(NewKeyboardLayoutEnabledLocalesFragment.class.getName())
.setArguments(arguments)
.launch();
mAutoInputDeviceIdentifier = inputDeviceIdentifier;
}
// Don't repeat the autoselection.
if (isAutoSelection(bundle, inputDeviceIdentifier)) {
showEnabledLocalesKeyboardLayoutList(inputDeviceIdentifier);
}
}
private static boolean isAutoSelection(Bundle bundle, InputDeviceIdentifier identifier) {
if (bundle != null && bundle.getParcelable(EXTRA_AUTO_SELECTION) != null) {
return false;
}
return identifier != null;
}
@Override
@@ -220,7 +232,6 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
pref.setOnPreferenceClickListener(
preference -> {
showEnabledLocalesKeyboardLayoutList(
hardKeyboardDeviceInfo.mDeviceName,
hardKeyboardDeviceInfo.mDeviceIdentifier);
return true;
});
@@ -246,8 +257,7 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
fragment.show(getActivity().getSupportFragmentManager(), "keyboardLayout");
}
private void showEnabledLocalesKeyboardLayoutList(String keyboardName,
InputDeviceIdentifier inputDeviceIdentifier) {
private void showEnabledLocalesKeyboardLayoutList(InputDeviceIdentifier inputDeviceIdentifier) {
Bundle arguments = new Bundle();
arguments.putParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER,
inputDeviceIdentifier);

View File

@@ -17,24 +17,27 @@
package com.android.settings.network.telephony;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
import com.android.settings.R;
import java.util.ArrayList;
import java.util.List;
/** Fragment to show a confirm dialog. The caller should implement onConfirmListener. */
public class ConfirmDialogFragment extends BaseDialogFragment
@@ -136,28 +139,10 @@ public class ConfirmDialogFragment extends BaseDialogFragment
dialogMessage.setVisibility(View.VISIBLE);
}
final ArrayAdapter<String> arrayAdapterItems = new ArrayAdapter<String>(
getContext(),
R.layout.sim_confirm_dialog_item_multiple_enabled_profiles_supported, list);
final ListView lvItems = content.findViewById(R.id.carrier_list);
if (lvItems != null) {
lvItems.setVisibility(View.VISIBLE);
lvItems.setAdapter(arrayAdapterItems);
lvItems.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Log.i(TAG, "list onClick =" + position);
Log.i(TAG, "list item =" + list.get(position));
if (position == list.size() - 1) {
// user select the "cancel" item;
informCaller(false, -1);
} else {
informCaller(true, position);
}
}
});
lvItems.setAdapter(new ButtonArrayAdapter(getContext(), list));
}
final LinearLayout infoOutline = content.findViewById(R.id.info_outline_layout);
if (infoOutline != null) {
@@ -197,4 +182,32 @@ public class ConfirmDialogFragment extends BaseDialogFragment
}
listener.onConfirm(getTagInCaller(), confirmed, itemPosition);
}
private class ButtonArrayAdapter extends ArrayAdapter<String> {
private final List<String> mList;
ButtonArrayAdapter(Context context, List<String> list) {
super(context, R.layout.sim_confirm_dialog_item_multiple_enabled_profiles_supported,
list);
mList = list;
}
@NonNull
@Override
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
View view = super.getView(position, convertView, parent);
view.setOnClickListener(v -> {
Log.i(TAG, "list onClick =" + position);
Log.i(TAG, "list item =" + mList.get(position));
if (position == mList.size() - 1) {
// user select the "cancel" item;
informCaller(false, -1);
} else {
informCaller(true, position);
}
});
return view;
}
}
}

View File

@@ -1,125 +0,0 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.notetask.shortcut
import android.app.Activity
import android.app.role.RoleManager
import android.app.role.RoleManager.ROLE_NOTES
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.graphics.drawable.Icon
import android.os.Bundle
import android.os.PersistableBundle
import android.os.UserHandle
import androidx.activity.ComponentActivity
import androidx.core.content.getSystemService
import com.android.settings.R
/**
* Activity responsible for create a shortcut for notes action. If the shortcut is enabled, a new
* shortcut will appear in the widget picker. If the shortcut is selected, the Activity here will be
* launched, creating a new shortcut for [CreateNoteTaskShortcutActivity], and will finish.
*
* IMPORTANT! The shortcut package name and class should be synchronized with SystemUI controller:
* [com.android.systemui.notetask.NoteTaskController#SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT].
*
* Changing the package name or class is a breaking change.
*
* @see <a
* href="https://developer.android.com/develop/ui/views/launch/shortcuts/creating-shortcuts#custom-pinned">Creating
* a custom shortcut activity</a>
*/
internal class CreateNoteTaskShortcutActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
val roleManager = requireNotNull(getSystemService<RoleManager>())
val shortcutManager = requireNotNull(getSystemService<ShortcutManager>())
super.onCreate(savedInstanceState)
val shortcutInfo = roleManager.createNoteShortcutInfoAsUser(context = this, user)
val shortcutIntent = shortcutManager.createShortcutResultIntent(shortcutInfo)
setResult(Activity.RESULT_OK, shortcutIntent)
finish()
}
private companion object {
private const val SHORTCUT_ID = "note_task_shortcut_id"
private const val EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE =
"extra_shortcut_badge_override_package"
private const val ACTION_LAUNCH_NOTE_TASK = "com.android.systemui.action.LAUNCH_NOTE_TASK"
private fun RoleManager.createNoteShortcutInfoAsUser(
context: Context,
user: UserHandle,
): ShortcutInfo? {
val systemUiComponent = context.getSystemUiComponent() ?: return null
val extras = PersistableBundle()
getDefaultRoleHolderAsUser(ROLE_NOTES, user)?.let { packageName ->
// Set custom app badge using the icon from ROLES_NOTES default app.
extras.putString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE, packageName)
}
val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
val intent = Intent(ACTION_LAUNCH_NOTE_TASK).apply {
setPackage(systemUiComponent.packageName)
}
// Creates a System UI context. That will let the ownership with SystemUI and allows it
// to perform updates such as enabling or updating the badge override package.
val systemUiContext = context.createPackageContext(
systemUiComponent.packageName,
/* flags */ 0,
)
return ShortcutInfo.Builder(systemUiContext, SHORTCUT_ID)
.setIntent(intent)
.setShortLabel(context.getString(R.string.note_task_shortcut_label))
.setLongLived(true)
.setIcon(icon)
.setExtras(extras)
.build()
}
private fun RoleManager.getDefaultRoleHolderAsUser(
role: String,
user: UserHandle,
): String? = getRoleHoldersAsUser(role, user).firstOrNull()
private fun Context.getSystemUiComponent(): ComponentName? {
val flattenName = getString(
com.android.internal.R.string.config_systemUIServiceComponent)
check(flattenName.isNotEmpty()) {
"No 'com.android.internal.R.string.config_systemUIServiceComponent' resource"
}
return try {
ComponentName.unflattenFromString(flattenName)
} catch (e: RuntimeException) {
val message = "Invalid component name defined by 'com.android.internal.R.string." +
"config_systemUIServiceComponent' resource: $flattenName"
throw IllegalStateException(message, e)
}
}
}
}

View File

@@ -48,8 +48,6 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.service.persistentdata.PersistentDataBlockManager;
import android.text.BidiFormatter;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
@@ -77,9 +75,9 @@ import com.android.settings.SetupWizardUtils;
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollActivity;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.safetycenter.LockScreenSafetySource;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settingslib.RestrictedPreference;
@@ -143,9 +141,6 @@ public class ChooseLockGeneric extends SettingsActivity {
*/
public static final String EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS = "choose_lock_generic_extras";
/** The character ' • ' to separate the setup choose options */
public static final String SEPARATOR = " \u2022 ";
@VisibleForTesting
static final int CONFIRM_EXISTING_REQUEST = 100;
@VisibleForTesting
@@ -662,32 +657,20 @@ public class ChooseLockGeneric extends SettingsActivity {
@VisibleForTesting
String getBiometricsPreferenceTitle(@NonNull ScreenLockType secureType) {
SpannableStringBuilder ssb = new SpannableStringBuilder();
BidiFormatter bidi = BidiFormatter.getInstance();
final boolean hasFingerprint = Utils.hasFingerprintHardware(getContext());
final boolean hasFace = Utils.hasFaceHardware(getContext());
final boolean isSuw = WizardManagerHelper.isAnySetupWizard(getIntent());
final boolean isFaceSupported =
hasFace && (!isSuw || BiometricUtils.isFaceSupportedInSuw(getContext()));
// Assume the flow is "Screen Lock" + "Face" + "Fingerprint"
if (mController != null) {
ssb.append(bidi.unicodeWrap(mController.getTitle(secureType)));
return BiometricUtils.getCombinedScreenLockOptions(getContext(),
mController.getTitle(secureType), hasFingerprint, isFaceSupported);
} else {
Log.e(TAG, "ChooseLockGenericController is null!");
return getResources().getString(R.string.error_title);
}
if (mFaceManager != null && mFaceManager.isHardwareDetected() && isFaceSupported()) {
ssb.append(bidi.unicodeWrap(SEPARATOR));
ssb.append(bidi.unicodeWrap(
getResources().getString(R.string.keywords_face_settings)));
}
if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
ssb.append(bidi.unicodeWrap(SEPARATOR));
ssb.append(bidi.unicodeWrap(
getResources().getString(R.string.security_settings_fingerprint)));
}
return ssb.toString();
}
private boolean isFaceSupported() {
return FeatureFactory.getFactory(getContext().getApplicationContext())
.getFaceFeatureProvider()
.isSetupWizardSupported(getContext().getApplicationContext());
}
private void setPreferenceTitle(ScreenLockType lock, @StringRes int title) {

View File

@@ -64,6 +64,8 @@ public final class ChooseLockSettingsHelper {
public static final String EXTRA_KEY_FOR_FACE = "for_face";
// For the paths where multiple biometric sensors exist
public static final String EXTRA_KEY_FOR_BIOMETRICS = "for_biometrics";
// For the paths where setup biometrics in suw flow
public static final String EXTRA_KEY_IS_SUW = "is_suw";
public static final String EXTRA_KEY_FOREGROUND_ONLY = "foreground_only";
public static final String EXTRA_KEY_REQUEST_GK_PW_HANDLE = "request_gk_pw_handle";
// Gatekeeper password handle, which can subsequently be used to generate Gatekeeper

View File

@@ -19,6 +19,7 @@ package com.android.settings.password;
import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
import android.app.RemoteServiceException.MissingRequestPasswordComplexityPermissionException;
@@ -43,6 +44,7 @@ import com.android.settings.R;
import com.android.settings.SetupWizardUtils;
import com.android.settings.utils.SettingsDividerItemDecoration;
import com.google.android.setupcompat.util.WizardManagerHelper;
import com.google.android.setupdesign.GlifPreferenceLayout;
import com.google.android.setupdesign.util.ThemeHelper;
@@ -187,14 +189,14 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric {
final String key = preference.getKey();
if (KEY_UNLOCK_SET_DO_LATER.equals(key)) {
// show warning.
final Intent intent = getActivity().getIntent();
SetupSkipDialog dialog = SetupSkipDialog.newInstance(
getActivity().getIntent()
.getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false),
/* isPatternMode= */ false,
/* isAlphaMode= */ false,
CREDENTIAL_TYPE_NONE,
intent.getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false),
/* forFingerprint= */ false,
/* forFace= */ false,
/* forBiometrics= */ false
/* forBiometrics= */ false,
WizardManagerHelper.isAnySetupWizard(intent)
);
dialog.show(getFragmentManager());
return true;

View File

@@ -16,6 +16,9 @@
package com.android.settings.password;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
@@ -31,6 +34,8 @@ import com.android.settings.R;
import com.android.settings.SetupRedactionInterstitial;
import com.android.settings.password.ChooseLockTypeDialogFragment.OnLockTypeSelectedListener;
import com.google.android.setupcompat.util.WizardManagerHelper;
/**
* Setup Wizard's version of ChooseLockPassword screen. It inherits the logic and basic structure
* from ChooseLockPassword class, and should remain similar to that behaviorally. This class should
@@ -113,12 +118,12 @@ public class SetupChooseLockPassword extends ChooseLockPassword {
final boolean forBiometrics = intent
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false);
final SetupSkipDialog dialog = SetupSkipDialog.newInstance(
mIsAlphaMode ? CREDENTIAL_TYPE_PASSWORD : CREDENTIAL_TYPE_PIN,
frpSupported,
/* isPatternMode= */ false,
mIsAlphaMode,
forFingerprint,
forFace,
forBiometrics);
forBiometrics,
WizardManagerHelper.isAnySetupWizard(intent));
ConfirmDeviceCredentialUtils.hideImeImmediately(
getActivity().getWindow().getDecorView());

View File

@@ -18,6 +18,8 @@ package com.android.settings.password;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -32,6 +34,8 @@ import androidx.fragment.app.Fragment;
import com.android.settings.R;
import com.android.settings.SetupRedactionInterstitial;
import com.google.android.setupcompat.util.WizardManagerHelper;
/**
* Setup Wizard's version of ChooseLockPattern screen. It inherits the logic and basic structure
* from ChooseLockPattern class, and should remain similar to that behaviorally. This class should
@@ -101,14 +105,13 @@ public class SetupChooseLockPattern extends ChooseLockPattern {
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
final boolean forBiometrics = intent
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false);
final SetupSkipDialog dialog = SetupSkipDialog.newInstance(
CREDENTIAL_TYPE_PATTERN,
frpSupported,
/* isPatternMode= */ true,
/* isAlphaMode= */ false,
forFingerprint,
forFace,
forBiometrics);
forBiometrics,
WizardManagerHelper.isAnySetupWizard(intent));
dialog.show(getFragmentManager());
return;
}

View File

@@ -16,6 +16,14 @@
package com.android.settings.password;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_IS_SUW;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -29,7 +37,10 @@ import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.fragment.app.FragmentManager;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
public class SetupSkipDialog extends InstrumentedDialogFragment
@@ -38,24 +49,23 @@ public class SetupSkipDialog extends InstrumentedDialogFragment
public static final String EXTRA_FRP_SUPPORTED = ":settings:frp_supported";
private static final String ARG_FRP_SUPPORTED = "frp_supported";
// The key indicates type of lock screen is pattern setup.
private static final String ARG_LOCK_TYPE_PATTERN = "lock_type_pattern";
// The key indicates type of screen lock credential types(PIN/Pattern/Password)
private static final String ARG_LOCK_CREDENTIAL_TYPE = "lock_credential_type";
// The key indicates type of lock screen setup is alphanumeric for password setup.
private static final String ARG_LOCK_TYPE_ALPHANUMERIC = "lock_type_alphanumeric";
private static final String TAG_SKIP_DIALOG = "skip_dialog";
public static final int RESULT_SKIP = Activity.RESULT_FIRST_USER + 10;
public static SetupSkipDialog newInstance(boolean isFrpSupported, boolean isPatternMode,
boolean isAlphanumericMode, boolean forFingerprint, boolean forFace,
boolean forBiometrics) {
public static SetupSkipDialog newInstance(@LockPatternUtils.CredentialType int credentialType,
boolean isFrpSupported, boolean forFingerprint, boolean forFace,
boolean forBiometrics, boolean isSuw) {
SetupSkipDialog dialog = new SetupSkipDialog();
Bundle args = new Bundle();
args.putInt(ARG_LOCK_CREDENTIAL_TYPE, credentialType);
args.putBoolean(ARG_FRP_SUPPORTED, isFrpSupported);
args.putBoolean(ARG_LOCK_TYPE_PATTERN, isPatternMode);
args.putBoolean(ARG_LOCK_TYPE_ALPHANUMERIC, isAlphanumericMode);
args.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, forFingerprint);
args.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, forFace);
args.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, forBiometrics);
args.putBoolean(EXTRA_KEY_FOR_FINGERPRINT, forFingerprint);
args.putBoolean(EXTRA_KEY_FOR_FACE, forFace);
args.putBoolean(EXTRA_KEY_FOR_BIOMETRICS, forBiometrics);
args.putBoolean(EXTRA_KEY_IS_SUW, isSuw);
dialog.setArguments(args);
return dialog;
}
@@ -70,59 +80,59 @@ public class SetupSkipDialog extends InstrumentedDialogFragment
return onCreateDialogBuilder().create();
}
private AlertDialog.Builder getBiometricsBuilder(
@LockPatternUtils.CredentialType int credentialType, boolean isSuw, boolean hasFace,
boolean hasFingerprint) {
final boolean isFaceSupported = hasFace && (!isSuw || BiometricUtils.isFaceSupportedInSuw(
getContext()));
final int msgResId;
final int screenLockResId;
switch (credentialType) {
case CREDENTIAL_TYPE_PATTERN:
screenLockResId = R.string.unlock_set_unlock_pattern_title;
msgResId = getPatternSkipMessageRes(hasFace && isFaceSupported, hasFingerprint);
break;
case CREDENTIAL_TYPE_PASSWORD:
screenLockResId = R.string.unlock_set_unlock_password_title;
msgResId = getPasswordSkipMessageRes(hasFace && isFaceSupported, hasFingerprint);
break;
case CREDENTIAL_TYPE_PIN:
default:
screenLockResId = R.string.unlock_set_unlock_pin_title;
msgResId = getPinSkipMessageRes(hasFace && isFaceSupported, hasFingerprint);
break;
}
return new AlertDialog.Builder(getContext())
.setPositiveButton(R.string.skip_lock_screen_dialog_button_label, this)
.setNegativeButton(R.string.cancel_lock_screen_dialog_button_label, this)
.setTitle(getSkipSetupTitle(screenLockResId, hasFingerprint,
hasFace && isFaceSupported))
.setMessage(msgResId);
}
@NonNull
public AlertDialog.Builder onCreateDialogBuilder() {
Bundle args = getArguments();
final boolean forFace =
args.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE);
final boolean forFingerprint =
args.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT);
final boolean forBiometrics =
args.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS);
final boolean isSuw = args.getBoolean(EXTRA_KEY_IS_SUW);
final boolean forBiometrics = args.getBoolean(EXTRA_KEY_FOR_BIOMETRICS);
final boolean forFace = args.getBoolean(EXTRA_KEY_FOR_FACE);
final boolean forFingerprint = args.getBoolean(EXTRA_KEY_FOR_FINGERPRINT);
@LockPatternUtils.CredentialType
final int credentialType = args.getInt(ARG_LOCK_CREDENTIAL_TYPE);
if (forFace || forFingerprint || forBiometrics) {
final boolean hasFace = forFace || forBiometrics;
final boolean hasFingerprint = forFingerprint || forBiometrics;
final int titleId;
final int msgResId;
if (args.getBoolean(ARG_LOCK_TYPE_PATTERN)) {
titleId = getPatternSkipTitleRes(hasFace, hasFingerprint);
msgResId = getPatternSkipMessageRes(hasFace, hasFingerprint);
} else if (args.getBoolean(ARG_LOCK_TYPE_ALPHANUMERIC)) {
titleId = getPasswordSkipTitleRes(hasFace, hasFingerprint);
msgResId = getPasswordSkipMessageRes(hasFace, hasFingerprint);
} else {
titleId = getPinSkipTitleRes(hasFace, hasFingerprint);
msgResId = getPinSkipMessageRes(hasFace, hasFingerprint);
}
return new AlertDialog.Builder(getContext())
.setPositiveButton(R.string.skip_lock_screen_dialog_button_label, this)
.setNegativeButton(R.string.cancel_lock_screen_dialog_button_label, this)
.setTitle(titleId)
.setMessage(msgResId);
} else {
return new AlertDialog.Builder(getContext())
.setPositiveButton(R.string.skip_anyway_button_label, this)
.setNegativeButton(R.string.go_back_button_label, this)
.setTitle(R.string.lock_screen_intro_skip_title)
.setMessage(args.getBoolean(ARG_FRP_SUPPORTED) ?
R.string.lock_screen_intro_skip_dialog_text_frp :
R.string.lock_screen_intro_skip_dialog_text);
final boolean hasFace = Utils.hasFaceHardware(getContext());
final boolean hasFingerprint = Utils.hasFingerprintHardware(getContext());
return getBiometricsBuilder(credentialType, isSuw, hasFace, hasFingerprint);
}
}
@StringRes
private int getPatternSkipTitleRes(boolean hasFace, boolean hasFingerprint) {
if (hasFace && hasFingerprint) {
return R.string.lock_screen_pattern_skip_biometrics_title;
} else if (hasFace) {
return R.string.lock_screen_pattern_skip_face_title;
} else if (hasFingerprint) {
return R.string.lock_screen_pattern_skip_fingerprint_title;
} else {
return R.string.lock_screen_pattern_skip_title;
}
return new AlertDialog.Builder(getContext())
.setPositiveButton(R.string.skip_anyway_button_label, this)
.setNegativeButton(R.string.go_back_button_label, this)
.setTitle(R.string.lock_screen_intro_skip_title)
.setMessage(args.getBoolean(ARG_FRP_SUPPORTED) ?
R.string.lock_screen_intro_skip_dialog_text_frp :
R.string.lock_screen_intro_skip_dialog_text);
}
@StringRes
@@ -138,19 +148,6 @@ public class SetupSkipDialog extends InstrumentedDialogFragment
}
}
@StringRes
private int getPasswordSkipTitleRes(boolean hasFace, boolean hasFingerprint) {
if (hasFace && hasFingerprint) {
return R.string.lock_screen_password_skip_biometrics_title;
} else if (hasFace) {
return R.string.lock_screen_password_skip_face_title;
} else if (hasFingerprint) {
return R.string.lock_screen_password_skip_fingerprint_title;
} else {
return R.string.lock_screen_password_skip_title;
}
}
@StringRes
private int getPasswordSkipMessageRes(boolean hasFace, boolean hasFingerprint) {
if (hasFace && hasFingerprint) {
@@ -164,19 +161,6 @@ public class SetupSkipDialog extends InstrumentedDialogFragment
}
}
@StringRes
private int getPinSkipTitleRes(boolean hasFace, boolean hasFingerprint) {
if (hasFace && hasFingerprint) {
return R.string.lock_screen_pin_skip_biometrics_title;
} else if (hasFace) {
return R.string.lock_screen_pin_skip_face_title;
} else if (hasFingerprint) {
return R.string.lock_screen_pin_skip_fingerprint_title;
} else {
return R.string.lock_screen_pin_skip_title;
}
}
@StringRes
private int getPinSkipMessageRes(boolean hasFace, boolean hasFingerprint) {
if (hasFace && hasFingerprint) {
@@ -190,6 +174,13 @@ public class SetupSkipDialog extends InstrumentedDialogFragment
}
}
private String getSkipSetupTitle(int screenTypeResId, boolean hasFingerprint,
boolean hasFace) {
return getString(R.string.lock_screen_skip_setup_title,
BiometricUtils.getCombinedScreenLockOptions(getContext(),
getString(screenTypeResId), hasFingerprint, hasFace));
}
@Override
public void onClick(DialogInterface dialog, int button) {
Activity activity = getActivity();

View File

@@ -106,6 +106,7 @@ public class DataUsageListTest {
ReflectionHelpers.setField(mDataUsageList, "services", mNetworkServices);
doReturn(mLoaderManager).when(mDataUsageList).getLoaderManager();
mDataUsageList.mLoadingViewController = mock(LoadingViewController.class);
doNothing().when(mDataUsageList).updateSubscriptionInfoEntity();
}
@Test

View File

@@ -41,11 +41,10 @@ public class DevelopmentMemtagPageTest {
mContext = RuntimeEnvironment.application;
}
@Ignore
@Test
public void getMetricsCategory_isSETTINGS_MEMTAG_CATEGORY() {
public void getMetricsCategory_isSETTINGS_DEVELOPMENT_MEMTAG_CATEGORY() {
assertThat(mMemtagPage.getMetricsCategory())
.isEqualTo(SettingsEnums.SETTINGS_MEMTAG_CATEGORY);
.isEqualTo(SettingsEnums.SETTINGS_DEVELOPMENT_MEMTAG_CATEGORY);
}
@Test

View File

@@ -57,17 +57,18 @@ public final class BatteryHistoricalLogUtilTest {
BatteryHistoricalLogUtil.writeLog(mContext, Action.APPLY, "pkg1", "logs");
BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter);
assertThat(mTestStringWriter.toString()).contains("pkg1\tAction:APPLY\tEvent:logs");
assertThat(mTestStringWriter.toString()).contains(
"pkg1\tAction:APPLY\tEvent:logs\tTimestamp:");
}
@Test
public void writeLog_multipleLogs_withCorrectCounts() {
for (int i = 0; i < BatteryHistoricalLogUtil.MAX_ENTRIES; i++) {
BatteryHistoricalLogUtil.writeLog(mContext, Action.MANUAL, "pkg" + i, "logs");
BatteryHistoricalLogUtil.writeLog(mContext, Action.LEAVE, "pkg" + i, "logs");
}
BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter);
assertThat(mTestStringWriter.toString().split("MANUAL").length).isEqualTo(41);
assertThat(mTestStringWriter.toString().split("LEAVE").length).isEqualTo(41);
}
@Test

View File

@@ -54,8 +54,7 @@ public class BatteryTipLoaderTest {
BatteryTip.TipType.BATTERY_DEFENDER,
BatteryTip.TipType.DOCK_DEFENDER,
BatteryTip.TipType.INCOMPATIBLE_CHARGER,
BatteryTip.TipType.HIGH_DEVICE_USAGE,
BatteryTip.TipType.SMART_BATTERY_MANAGER};
BatteryTip.TipType.HIGH_DEVICE_USAGE};
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private BatteryUsageStats mBatteryUsageStats;
@Mock

View File

@@ -79,6 +79,7 @@ import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.shadows.ShadowPersistentDataBlockManager;
@@ -98,6 +99,8 @@ public class ChooseLockGenericTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
private ActivityController<ChooseLockGeneric> mActivityController;
private FakeFeatureFactory mFakeFeatureFactory;
private ChooseLockGenericFragment mFragment;
private ChooseLockGeneric mActivity;
@@ -109,7 +112,8 @@ public class ChooseLockGenericTest {
@Before
public void setUp() {
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mActivity = Robolectric.buildActivity(ChooseLockGeneric.class)
mActivityController = Robolectric.buildActivity(ChooseLockGeneric.class);
mActivity = mActivityController
.create()
.start()
.postCreate(null)
@@ -314,6 +318,20 @@ public class ChooseLockGenericTest {
assertThat(mActivity.isFinishing()).isTrue();
}
@Test
public void securedScreenLock_notChangingConfig_notWaitForConfirmation_onStopFinishSelf() {
Intent intent = new Intent().putExtra(
LockPatternUtils.PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
intent.putExtra("waiting_for_confirmation", true);
initActivity(intent);
mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
mActivityController.configurationChange();
mActivityController.stop();
assertThat(mActivity.isFinishing()).isTrue();
}
@Test
public void onPreferenceTreeClick_fingerprintPassesMinComplexityInfoOntoNextActivity() {
Intent intent = new Intent(ACTION_SET_NEW_PASSWORD)
@@ -534,10 +552,10 @@ public class ChooseLockGenericTest {
assertThat(passwordIntent.getIntExtra(ChooseLockPassword.EXTRA_KEY_MIN_COMPLEXITY,
PASSWORD_COMPLEXITY_NONE)).isEqualTo(PASSWORD_COMPLEXITY_LOW);
final String supportFingerprint = mActivity.getResources().getString(
R.string.security_settings_fingerprint);
final String supportFace = mActivity.getResources().getString(
R.string.keywords_face_settings);
final String supportFingerprint = capitalize(mActivity.getResources().getString(
R.string.security_settings_fingerprint));
final String supportFace = capitalize(mActivity.getResources().getString(
R.string.keywords_face_settings));
assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains(
supportFingerprint);
@@ -563,4 +581,8 @@ public class ChooseLockGenericTest {
.create().start().postCreate(null).resume().get();
mActivity.getSupportFragmentManager().beginTransaction().add(mFragment, null).commitNow();
}
private static String capitalize(final String input) {
return Character.toUpperCase(input.charAt(0)) + input.substring(1);
}
}

View File

@@ -21,6 +21,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_SETUP_FLOW;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -43,6 +44,7 @@ import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowPasswordUtils;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settings.utils.ActivityControllerWrapper;
import com.google.android.setupdesign.GlifPreferenceLayout;
@@ -100,6 +102,7 @@ public class SetupChooseLockGenericTest {
@Test
public void setupChooseLockGenericPasswordComplexityExtraWithoutPermission() {
Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN");
intent.putExtra(EXTRA_IS_SETUP_FLOW, true);
intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
SetupChooseLockGeneric activity =
Robolectric.buildActivity(SetupChooseLockGeneric.class, intent).create().get();
@@ -114,6 +117,7 @@ public class SetupChooseLockGenericTest {
ShadowPasswordUtils.addGrantedPermission(REQUEST_PASSWORD_COMPLEXITY);
Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN");
intent.putExtra(EXTRA_IS_SETUP_FLOW, true);
intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
SetupChooseLockGeneric activity =
Robolectric.buildActivity(SetupChooseLockGeneric.class, intent).create().get();
@@ -124,7 +128,8 @@ public class SetupChooseLockGenericTest {
@Test
public void setupChooseLockGenericUsingDescriptionTextOfGlifLayout() {
SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(false);
SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true, true,
false);
GlifPreferenceLayout view = getViewOfSetupChooseLockGenericFragment(fragment);
assertThat(TextUtils.isEmpty(view.getDescriptionText())).isFalse();
assertThat(view.getDescriptionText().toString()).isEqualTo(fragment.loadDescriptionText());
@@ -132,47 +137,24 @@ public class SetupChooseLockGenericTest {
@Test
public void setupChooseLockGenericUsingDescriptionTextOfGlifLayoutForBiometric() {
SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true);
SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true, true,
true);
GlifPreferenceLayout view = getViewOfSetupChooseLockGenericFragment(fragment);
assertThat(TextUtils.isEmpty(view.getDescriptionText())).isFalse();
assertThat(view.getDescriptionText().toString()).isEqualTo(fragment.loadDescriptionText());
}
@Test
public void updatePreferenceTextShowScreenLockAndFingerprint() {
when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn(
false);
SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true);
final String supportFingerprint = fragment.getResources().getString(
R.string.security_settings_fingerprint);
final String supportFace = fragment.getResources().getString(
R.string.keywords_face_settings);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains(
supportFingerprint);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).doesNotContain(
supportFace);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).contains(
supportFingerprint);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).doesNotContain(
supportFace);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).contains(
supportFingerprint);
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).doesNotContain(
supportFace);
}
@Test
public void updatePreferenceTextShowScreenLockAndShowFaceAndShowFingerprint() {
when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn(
true);
SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true);
SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true, true,
true);
final String supportFingerprint = fragment.getResources().getString(
R.string.security_settings_fingerprint);
final String supportFace = fragment.getResources().getString(
R.string.keywords_face_settings);
final String supportFingerprint = capitalize(fragment.getResources().getString(
R.string.security_settings_fingerprint));
final String supportFace = capitalize(fragment.getResources().getString(
R.string.keywords_face_settings));
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains(
supportFingerprint);
@@ -192,12 +174,13 @@ public class SetupChooseLockGenericTest {
public void updatePreferenceTextShowScreenLockAndShowFingerprint() {
when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn(
false);
SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true);
SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(false, false,
true);
final String supportFingerprint = fragment.getResources().getString(
R.string.security_settings_fingerprint);
final String supportFace = fragment.getResources().getString(
R.string.keywords_face_settings);
final String supportFingerprint = capitalize(fragment.getResources().getString(
R.string.security_settings_fingerprint));
final String supportFace = capitalize(fragment.getResources().getString(
R.string.keywords_face_settings));
assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains(
supportFingerprint);
@@ -213,16 +196,18 @@ public class SetupChooseLockGenericTest {
supportFace);
}
private SetupChooseLockGenericFragment getFragmentOfSetupChooseLockGeneric(boolean biometric) {
private SetupChooseLockGenericFragment getFragmentOfSetupChooseLockGeneric(
boolean forFingerprint, boolean forFace, boolean forBiometric) {
ShadowPasswordUtils.addGrantedPermission(REQUEST_PASSWORD_COMPLEXITY);
Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN");
intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, biometric);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, biometric);
// TODO(b/275023433) This presents the activity from being made 'visible` is workaround
SetupChooseLockGeneric activity =
Robolectric.buildActivity(SetupChooseLockGeneric.class,
intent).create().start().postCreate(null).resume().get();
intent.putExtra(EXTRA_IS_SETUP_FLOW, true);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, forFingerprint);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, forFace);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, forBiometric);
SetupChooseLockGeneric activity = (SetupChooseLockGeneric) ActivityControllerWrapper.setup(
Robolectric.buildActivity(SetupChooseLockGeneric.class, intent)).get();
List<Fragment> fragments = activity.getSupportFragmentManager().getFragments();
assertThat(fragments).isNotNull();
@@ -238,4 +223,8 @@ public class SetupChooseLockGenericTest {
return (GlifPreferenceLayout) fragment.getView();
}
private static String capitalize(final String input) {
return Character.toUpperCase(input.charAt(0)) + input.substring(1);
}
}

View File

@@ -30,7 +30,6 @@ import android.widget.Button;
import androidx.appcompat.app.AlertDialog;
import com.android.settings.R;
import com.android.settings.utils.ActivityControllerWrapper;
import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment;
import com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment.Stage;
import com.android.settings.password.ChooseLockPassword.IntentBuilder;
@@ -40,6 +39,7 @@ import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settings.utils.ActivityControllerWrapper;
import com.android.settings.widget.ScrollToParentEditText;
import com.google.android.setupcompat.PartnerCustomizationLayout;
@@ -93,7 +93,6 @@ public class SetupChooseLockPasswordTest {
application,
new IntentBuilder(application).build());
//ActivityController.of(new SetupChooseLockPassword(), intent).setup().get();
ActivityControllerWrapper.setup(
Robolectric.buildActivity(SetupChooseLockPassword.class, intent)).get();
}
@@ -204,7 +203,6 @@ public class SetupChooseLockPasswordTest {
intent.putExtra(ChooseLockGenericFragment.EXTRA_SHOW_OPTIONS_BUTTON, true);
return (SetupChooseLockPassword) ActivityControllerWrapper.setup(
Robolectric.buildActivity(SetupChooseLockPassword.class, intent)).get();
//return ActivityController.of(new SetupChooseLockPassword(), intent).setup().get();
}
@Implements(ChooseLockGenericController.class)

View File

@@ -38,10 +38,10 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
import com.android.internal.widget.LockPatternView.Cell;
import com.android.internal.widget.LockPatternView.DisplayMode;
import com.android.settings.password.ChooseLockPattern.ChooseLockPatternFragment;
import com.android.settings.password.ChooseLockPattern.IntentBuilder;
import com.android.settings.R;
import com.android.settings.SetupRedactionInterstitial;
import com.android.settings.password.ChooseLockPattern.ChooseLockPatternFragment;
import com.android.settings.password.ChooseLockPattern.IntentBuilder;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowUtils;
@@ -84,7 +84,7 @@ public class SetupChooseLockPatternTest {
new IntentBuilder(application)
.setUserId(UserHandle.myUserId())
.build());
//mActivity = ActivityController.of(new SetupChooseLockPattern(), intent).setup().get();
mActivity = (SetupChooseLockPattern) ActivityControllerWrapper.setup(
Robolectric.buildActivity(SetupChooseLockPattern.class, intent)).get();
}

View File

@@ -16,18 +16,34 @@
package com.android.settings.password;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import androidx.fragment.app.FragmentActivity;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settings.utils.ActivityControllerWrapper;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
@@ -39,12 +55,25 @@ import org.robolectric.shadows.ShadowApplication;
@Config(shadows = {ShadowUtils.class, ShadowAlertDialog.class})
public class SetupSkipDialogTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
private FingerprintManager mFingerprintManager;
@Mock
private FaceManager mFaceManager;
private FragmentActivity mActivity;
private FakeFeatureFactory mFakeFeatureFactory;
@Before
public void setUp() {
ShadowUtils.setFingerprintManager(mFingerprintManager);
ShadowUtils.setFaceManager(mFaceManager);
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mActivity = (FragmentActivity) ActivityControllerWrapper.setup(
Robolectric.buildActivity(FragmentActivity.class)).get();
when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn(
true);
}
private ShadowAlertDialog getShadowAlertDialog() {
@@ -55,10 +84,33 @@ public class SetupSkipDialogTest {
return shadowAlertDialog;
}
private String getSkipSetupTitle(int credentialType, boolean hasFingerprint,
boolean hasFace) {
final int screenLockResId;
switch (credentialType) {
case CREDENTIAL_TYPE_PATTERN:
screenLockResId = R.string.unlock_set_unlock_pattern_title;
break;
case CREDENTIAL_TYPE_PASSWORD:
screenLockResId = R.string.unlock_set_unlock_password_title;
break;
case CREDENTIAL_TYPE_PIN:
default:
screenLockResId = R.string.unlock_set_unlock_pin_title;
break;
}
return mActivity.getString(R.string.lock_screen_skip_setup_title,
BiometricUtils.getCombinedScreenLockOptions(mActivity,
mActivity.getString(screenLockResId), hasFingerprint, hasFace));
}
@Test
public void frpMessages_areShownCorrectly_whenNotSupported() {
when(mFaceManager.isHardwareDetected()).thenReturn(false);
when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
SetupSkipDialog setupSkipDialog =
SetupSkipDialog.newInstance(false, false, false, false, false, false);
SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PIN, false, false, false, false, true);
setupSkipDialog.show(mActivity.getSupportFragmentManager());
ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog();
@@ -70,8 +122,11 @@ public class SetupSkipDialogTest {
@Test
public void frpMessages_areShownCorrectly_whenSupported() {
when(mFaceManager.isHardwareDetected()).thenReturn(false);
when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
SetupSkipDialog setupSkipDialog =
SetupSkipDialog.newInstance(true, false, false, false, false, false);
SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PIN, true, false, false, false, true);
setupSkipDialog.show(mActivity.getSupportFragmentManager());
ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog();
@@ -83,117 +138,175 @@ public class SetupSkipDialogTest {
@Test
public void dialogMessage_whenSkipPinSetupForFace_shouldShownCorrectly() {
SetupSkipDialog setupSkipDialog =
SetupSkipDialog.newInstance(true, false, false, false, true, false);
final boolean hasFace = true;
final boolean hasFingerprint = false;
when(mFaceManager.isHardwareDetected()).thenReturn(hasFace);
when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint);
SetupSkipDialog setupSkipDialog = SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PIN, false,
false, true, false, true);
setupSkipDialog.show(mActivity.getSupportFragmentManager());
ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog();
assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_pin_skip_face_title));
getSkipSetupTitle(CREDENTIAL_TYPE_PIN, hasFingerprint, hasFace));
assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_pin_skip_face_message));
}
@Test
public void dialogMessage_whenSkipPasswordSetupForFace_shouldShownCorrectly() {
SetupSkipDialog setupSkipDialog =
SetupSkipDialog.newInstance(true, false, true, false, true, false);
final boolean hasFace = true;
final boolean hasFingerprint = false;
when(mFaceManager.isHardwareDetected()).thenReturn(hasFace);
when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint);
SetupSkipDialog setupSkipDialog = SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PASSWORD,
false, hasFingerprint, hasFace, false, true);
setupSkipDialog.show(mActivity.getSupportFragmentManager());
ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog();
assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_password_skip_face_title));
getSkipSetupTitle(CREDENTIAL_TYPE_PASSWORD, hasFingerprint, hasFace));
assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_password_skip_face_message));
}
@Test
public void dialogMessage_whenSkipPatternSetupForFace_shouldShownCorrectly() {
final boolean hasFace = true;
final boolean hasFingerprint = false;
when(mFaceManager.isHardwareDetected()).thenReturn(hasFace);
when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint);
SetupSkipDialog setupSkipDialog =
SetupSkipDialog.newInstance(true, true, false, false, true, false);
SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PATTERN, true, false, true, false,
true);
setupSkipDialog.show(mActivity.getSupportFragmentManager());
ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog();
assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_pattern_skip_face_title));
getSkipSetupTitle(CREDENTIAL_TYPE_PATTERN, hasFingerprint, hasFace));
assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_pattern_skip_face_message));
}
@Test
public void dialogMessage_whenSkipPinSetupForFingerprint_shouldShownCorrectly() {
final boolean hasFace = false;
final boolean hasFingerprint = true;
when(mFaceManager.isHardwareDetected()).thenReturn(hasFace);
when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint);
SetupSkipDialog setupSkipDialog =
SetupSkipDialog.newInstance(true, false, false, true, false, false);
SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PIN, true, true, false, false, true);
setupSkipDialog.show(mActivity.getSupportFragmentManager());
ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog();
assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_pin_skip_fingerprint_title));
getSkipSetupTitle(CREDENTIAL_TYPE_PIN, hasFingerprint, hasFace));
assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_pin_skip_fingerprint_message));
}
@Test
public void dialogMessage_whenSkipPasswordSetupForFingerprint_shouldShownCorrectly() {
final boolean hasFace = false;
final boolean hasFingerprint = true;
when(mFaceManager.isHardwareDetected()).thenReturn(hasFace);
when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint);
SetupSkipDialog setupSkipDialog =
SetupSkipDialog.newInstance(true, false, true, true, false, false);
SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PASSWORD, true, true, false, false,
true);
setupSkipDialog.show(mActivity.getSupportFragmentManager());
ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog();
assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_password_skip_fingerprint_title));
getSkipSetupTitle(CREDENTIAL_TYPE_PASSWORD, hasFingerprint, hasFace));
assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_password_skip_fingerprint_message));
}
@Test
public void dialogMessage_whenSkipPatternSetupForFingerprint_shouldShownCorrectly() {
SetupSkipDialog setupSkipDialog =
SetupSkipDialog.newInstance(true, true, false, true, false, false);
final boolean hasFace = false;
final boolean hasFingerprint = true;
when(mFaceManager.isHardwareDetected()).thenReturn(hasFace);
when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint);
SetupSkipDialog setupSkipDialog = SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PATTERN, true,
true, false, false, true);
setupSkipDialog.show(mActivity.getSupportFragmentManager());
ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog();
assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_pattern_skip_fingerprint_title));
getSkipSetupTitle(CREDENTIAL_TYPE_PATTERN, hasFingerprint, hasFace));
assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_pattern_skip_fingerprint_message));
}
@Test
public void dialogMessage_whenSkipPinSetupForBiometrics_shouldShownCorrectly() {
final boolean hasFace = true;
final boolean hasFingerprint = true;
when(mFaceManager.isHardwareDetected()).thenReturn(hasFace);
when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint);
SetupSkipDialog setupSkipDialog =
SetupSkipDialog.newInstance(true, false, false, false, false, true);
SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PIN, true, false, false, true, true);
setupSkipDialog.show(mActivity.getSupportFragmentManager());
ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog();
assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_pin_skip_biometrics_title));
getSkipSetupTitle(CREDENTIAL_TYPE_PIN, hasFingerprint, hasFace));
assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_pin_skip_biometrics_message));
}
@Test
public void dialogMessage_whenSkipPasswordSetupForBiometrics_shouldShownCorrectly() {
final boolean hasFace = true;
final boolean hasFingerprint = true;
when(mFaceManager.isHardwareDetected()).thenReturn(hasFace);
when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint);
SetupSkipDialog setupSkipDialog =
SetupSkipDialog.newInstance(true, false, true, false, false, true);
SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PASSWORD, true, false, false, true,
true);
setupSkipDialog.show(mActivity.getSupportFragmentManager());
ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog();
assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_password_skip_biometrics_title));
getSkipSetupTitle(CREDENTIAL_TYPE_PASSWORD, hasFingerprint, hasFace));
assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_password_skip_biometrics_message));
}
@Test
public void dialogMessage_whenSkipPatternSetupForBiometrics_shouldShownCorrectly() {
final boolean hasFace = true;
final boolean hasFingerprint = true;
when(mFaceManager.isHardwareDetected()).thenReturn(hasFace);
when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint);
SetupSkipDialog setupSkipDialog =
SetupSkipDialog.newInstance(true, true, false, false, false, true);
SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PATTERN, true, false, false, true,
true);
setupSkipDialog.show(mActivity.getSupportFragmentManager());
ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog();
assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_pattern_skip_biometrics_title));
getSkipSetupTitle(CREDENTIAL_TYPE_PATTERN, hasFingerprint, hasFace));
assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo(
mActivity.getString(R.string.lock_screen_pattern_skip_biometrics_message));
}