Snap for 9556278 from 2d2db1f711 to udc-release

Change-Id: Ia179f19b0d54e8d08bfbb4780b0d23552344197b
This commit is contained in:
Android Build Coastguard Worker
2023-02-03 02:29:24 +00:00
49 changed files with 1356 additions and 262 deletions

View File

@@ -667,4 +667,25 @@
<string name="reset_internet_text" product="default">This will end your phone call</string>
<!-- Description for interrupting the voice call alert. [CHAR_LIMIT=NONE] -->
<string name="reset_internet_text" product="tablet">This will end your phone call</string>
<!-- An explanation text that the pattern needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_pattern_details_frp" product="default">Your phone was reset to factory settings. To use this phone, enter your previous pattern.</string>
<!-- An explanation text that the pattern needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_pattern_details_frp" product="tablet">Your tablet was reset to factory settings. To use this tablet, enter your previous pattern.</string>
<!-- An explanation text that the pattern needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_pattern_details_frp" product="device">Your device was reset to factory settings. To use this device, enter your previous pattern.</string>
<!-- An explanation text that the pin needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_pin_details_frp" product="default">Your phone was reset to factory settings. To use this phone, enter your previous PIN.</string>
<!-- An explanation text that the pin needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_pin_details_frp" product="tablet">Your tablet was reset to factory settings. To use this tablet, enter your previous PIN.</string>
<!-- An explanation text that the pin needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_pin_details_frp" product="device">Your device was reset to factory settings. To use this device, enter your previous PIN.</string>
<!-- An explanation text that the password needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_password_details_frp" product="default">Your phone was reset to factory settings. To use this phone, enter your previous password.</string>
<!-- An explanation text that the password needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_password_details_frp" product="tablet">Your tablet was reset to factory settings. To use this tablet, enter your previous password.</string>
<!-- An explanation text that the password needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_password_details_frp" product="device">Your device was reset to factory settings. To use this device, enter your previous password.</string>
</resources>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1044,6 +1044,10 @@
<string name="no_screen_lock_issue_summary">For added security, set a PIN, pattern, or password for this device.</string>
<!-- 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>
<!-- 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>
<!-- Unlock Picker Settings --><skip />
@@ -3330,27 +3334,6 @@
continue. [CHAR LIMIT=100] -->
<string name="lockpassword_strong_auth_required_work_password">For added security, enter your work password</string>
<!-- An explanation text that the pattern needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_pattern_details_frp" product="default">Your phone was reset to factory settings. To use this phone, enter your previous pattern.</string>
<!-- An explanation text that the pattern needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_pattern_details_frp" product="tablet">Your tablet was reset to factory settings. To use this tablet, enter your previous pattern.</string>
<!-- An explanation text that the pattern needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_pattern_details_frp" product="device">Your device was reset to factory settings. To use this device, enter your previous pattern.</string>
<!-- An explanation text that the pin needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_pin_details_frp" product="default">Your phone was reset to factory settings. To use this phone, enter your previous PIN.</string>
<!-- An explanation text that the pin needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_pin_details_frp" product="tablet">Your tablet was reset to factory settings. To use this tablet, enter your previous PIN.</string>
<!-- An explanation text that the pin needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_pin_details_frp" product="device">Your device was reset to factory settings. To use this device, enter your previous PIN.</string>
<!-- An explanation text that the password needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_password_details_frp" product="default">Your phone was reset to factory settings. To use this phone, enter your previous password.</string>
<!-- An explanation text that the password needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_password_details_frp" product="tablet">Your tablet was reset to factory settings. To use this tablet, enter your previous password.</string>
<!-- An explanation text that the password needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_password_details_frp" product="device">Your device was reset to factory settings. To use this device, enter your previous password.</string>
<!-- Header shown when pattern needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
<string name="lockpassword_confirm_your_pattern_header_frp">Verify pattern</string>
<!-- Header shown when the pin needs to be solved because the device was factory reset. [CHAR LIMIT=100] -->
@@ -3824,6 +3807,8 @@
<string name="language_and_input_for_work_category_title">Work profile keyboards &amp; tools</string>
<!-- Title for the 'Virtual keyboards for work' preference. [CHAR LIMIT=45] -->
<string name="virtual_keyboards_for_work_title">On-screen keyboard for work</string>
<!-- Summary text for none selected keyboard default layout -->
<string name="keyboard_default_layout">Default</string>
<!-- Title for the button to trigger the 'trackpad settings' page if only connect with a touchpad. [CHAR LIMIT=35] -->
<string name="trackpad_settings">Touchpad</string>
@@ -10255,14 +10240,14 @@
<!-- Apps > App Details > Wifi access > Description. [CHAR LIMIT=NONE] -->
<string name="change_wifi_state_app_detail_summary">Allow this app to turn Wi-Fi on or off, scan and connect to Wi-Fi networks, add or remove networks, or start a local-only hotspot</string>
<!-- Title for Nfc Tag apps control [CHAR LIMIT=35] -->
<string name="change_nfc_tag_apps_title">NFC Tag apps control</string>
<!-- Title for NFC launch [CHAR LIMIT=35] -->
<string name="change_nfc_tag_apps_title">NFC launch</string>
<!-- Apps > App Details > Nfc Tag apps control > Switch title. [CHAR LIMIT=NONE] -->
<string name="change_nfc_tag_apps_detail_switch">Allow app to popup upon NFC tags detected</string>
<!-- Apps > App Details > Nfc launch > Switch title. [CHAR LIMIT=NONE] -->
<string name="change_nfc_tag_apps_detail_switch">Allow launch on NFC scan</string>
<!-- Apps > App Details > Nfc Tag apps control > Description. [CHAR LIMIT=NONE] -->
<string name="change_nfc_tag_apps_detail_summary">Allow this app to launch and get tag contents when the device detests NFC tags</string>
<!-- Apps > App Details > Nfc launch > Description. [CHAR LIMIT=NONE] -->
<string name="change_nfc_tag_apps_detail_summary">Allow this app to launch when a NFC tag is scanned.\nIf this permission is on, the app will be available as an option whenever a tag is detected.</string>
<!-- Title for media output settings -->
<string name="media_output_title">Play media to</string>

View File

@@ -27,6 +27,7 @@
android:key="bubbles_illustration"
settings:searchable="false"
app:lottie_rawRes="@raw/lottie_bubbles"
settings:dynamicColor="true"
settings:controller="com.android.settings.notification.BubbleNotificationIllustrationPreferenceController"/>
<com.android.settingslib.widget.MainSwitchPreference

View File

@@ -26,6 +26,7 @@
<com.android.settingslib.widget.IllustrationPreference
android:key="gesture_power_menu_video"
settings:searchable="false"
settings:dynamicColor="true"
settings:lottie_imageAssetsFolder="button_nav_menu"
settings:lottie_rawRes="@raw/lottie_button_nav_menu"/>

View File

@@ -16,8 +16,5 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/physical_keyboard_title">
<PreferenceCategory
android:key="enabled_locales_keyboard_layout"
android:title="@string/enabled_locales_keyboard_layout">
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -1277,4 +1277,16 @@ public final class Utils extends com.android.settingslib.Utils {
}
return -1;
}
/**
* Returns if the current user is able to use Dreams.
*/
public static boolean canCurrentUserDream(Context context) {
final UserHandle mainUser = context.getSystemService(UserManager.class).getMainUser();
if (mainUser == null) {
return false;
}
return context.createContextAsUser(mainUser, 0).getSystemService(UserManager.class)
.isUserForeground();
}
}

View File

@@ -1,6 +1,7 @@
# Default reviewers for this and subdirectories.
danielnorman@google.com
menghanli@google.com
thomasli@google.com
per-file HapticFeedbackIntensityPreferenceController.java = michaelwr@google.com
per-file *Vibration* = michaelwr@google.com

View File

@@ -24,8 +24,11 @@ import android.hardware.fingerprint.FingerprintManager;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.password.ChooseLockSettingsHelper;
import java.util.function.Function;
/**
* Helper for {@link BiometricEnrollActivity} when multiple sensors exist on a device.
*/
@@ -45,14 +48,39 @@ public class MultiBiometricEnrollHelper {
private final int mUserId;
private final boolean mRequestEnrollFace;
private final boolean mRequestEnrollFingerprint;
private final FingerprintManager mFingerprintManager;
private final FaceManager mFaceManager;
private final Intent mFingerprintEnrollIntroductionIntent;
private final Intent mFaceEnrollIntroductionIntent;
private Function<Long, byte[]> mGatekeeperHatSupplier;
@VisibleForTesting
MultiBiometricEnrollHelper(@NonNull FragmentActivity activity, int userId,
boolean enrollFace, boolean enrollFingerprint, long gkPwHandle) {
boolean enrollFace, boolean enrollFingerprint, long gkPwHandle,
FingerprintManager fingerprintManager,
FaceManager faceManager, Intent fingerprintEnrollIntroductionIntent,
Intent faceEnrollIntroductionIntent, Function<Long, byte[]> gatekeeperHatSupplier) {
mActivity = activity;
mUserId = userId;
mGkPwHandle = gkPwHandle;
mRequestEnrollFace = enrollFace;
mRequestEnrollFingerprint = enrollFingerprint;
mFingerprintManager = fingerprintManager;
mFaceManager = faceManager;
mFingerprintEnrollIntroductionIntent = fingerprintEnrollIntroductionIntent;
mFaceEnrollIntroductionIntent = faceEnrollIntroductionIntent;
mGatekeeperHatSupplier = gatekeeperHatSupplier;
}
MultiBiometricEnrollHelper(@NonNull FragmentActivity activity, int userId,
boolean enrollFace, boolean enrollFingerprint, long gkPwHandle) {
this(activity, userId, enrollFace, enrollFingerprint, gkPwHandle,
activity.getSystemService(FingerprintManager.class),
activity.getSystemService(FaceManager.class),
BiometricUtils.getFingerprintIntroIntent(activity, activity.getIntent()),
BiometricUtils.getFaceIntroIntent(activity, activity.getIntent()),
(challenge) -> BiometricUtils.requestGatekeeperHat(activity, gkPwHandle,
userId, challenge));
}
void startNextStep() {
@@ -67,45 +95,39 @@ public class MultiBiometricEnrollHelper {
}
private void launchFaceEnroll() {
final FaceManager faceManager = mActivity.getSystemService(FaceManager.class);
faceManager.generateChallenge(mUserId, (sensorId, userId, challenge) -> {
final byte[] hardwareAuthToken = BiometricUtils.requestGatekeeperHat(mActivity,
mGkPwHandle, mUserId, challenge);
final Intent faceIntent = BiometricUtils.getFaceIntroIntent(mActivity,
mActivity.getIntent());
faceIntent.putExtra(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId);
faceIntent.putExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge);
BiometricUtils.launchEnrollForResult(mActivity, faceIntent, REQUEST_FACE_ENROLL,
hardwareAuthToken, mGkPwHandle, mUserId);
mFaceManager.generateChallenge(mUserId, (sensorId, userId, challenge) -> {
final byte[] hardwareAuthToken = mGatekeeperHatSupplier.apply(challenge);
mFaceEnrollIntroductionIntent.putExtra(
BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId);
mFaceEnrollIntroductionIntent.putExtra(
BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge);
BiometricUtils.launchEnrollForResult(mActivity, mFaceEnrollIntroductionIntent,
REQUEST_FACE_ENROLL, hardwareAuthToken, mGkPwHandle, mUserId);
});
}
private void launchFingerprintEnroll() {
final FingerprintManager fingerprintManager = mActivity
.getSystemService(FingerprintManager.class);
fingerprintManager.generateChallenge(mUserId, ((sensorId, userId, challenge) -> {
final byte[] hardwareAuthToken = BiometricUtils.requestGatekeeperHat(mActivity,
mGkPwHandle, mUserId, challenge);
final Intent intent = BiometricUtils.getFingerprintIntroIntent(mActivity,
mActivity.getIntent());
intent.putExtra(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId);
intent.putExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge);
mFingerprintManager.generateChallenge(mUserId, ((sensorId, userId, challenge) -> {
final byte[] hardwareAuthToken = mGatekeeperHatSupplier.apply(challenge);
mFingerprintEnrollIntroductionIntent.putExtra(
BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId);
mFingerprintEnrollIntroductionIntent.putExtra(
BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge);
if (mRequestEnrollFace) {
// Give FingerprintEnroll a pendingIntent pointing to face enrollment, so that it
// can be started when user skips or finishes fingerprint enrollment.
// FLAG_UPDATE_CURRENT ensures it is launched with the most recent values.
final Intent faceIntent = BiometricUtils.getFaceIntroIntent(mActivity,
mActivity.getIntent());
faceIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
faceIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
mGkPwHandle);
mFaceEnrollIntroductionIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
mFaceEnrollIntroductionIntent.putExtra(
ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, mGkPwHandle);
final PendingIntent faceAfterFp = PendingIntent.getActivity(mActivity,
0 /* requestCode */, faceIntent,
0 /* requestCode */, mFaceEnrollIntroductionIntent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
intent.putExtra(EXTRA_ENROLL_AFTER_FINGERPRINT, faceAfterFp);
mFingerprintEnrollIntroductionIntent.putExtra(EXTRA_ENROLL_AFTER_FINGERPRINT,
faceAfterFp);
}
BiometricUtils.launchEnrollForResult(mActivity, intent, REQUEST_FINGERPRINT_ENROLL,
hardwareAuthToken, mGkPwHandle, mUserId);
BiometricUtils.launchEnrollForResult(mActivity, mFingerprintEnrollIntroductionIntent,
REQUEST_FINGERPRINT_ENROLL, hardwareAuthToken, mGkPwHandle, mUserId);
}));
}
}

View File

@@ -20,6 +20,7 @@ import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.UserManager;
import androidx.annotation.Nullable;
@@ -86,6 +87,18 @@ public class CombinedBiometricStatusUtils {
return faceConsentRequired && fpConsentRequired ? faceAdmin : null;
}
/**
* Returns the title of combined biometric settings entity.
*/
public String getTitle() {
UserManager userManager = mContext.getSystemService(UserManager.class);
if (userManager != null && userManager.isProfile()) {
return mContext.getString(R.string.security_settings_work_biometric_preference_title);
} else {
return mContext.getString(R.string.security_settings_biometric_preference_title);
}
}
/**
* Returns the summary of combined biometric settings entity.
*/

View File

@@ -19,6 +19,7 @@ package com.android.settings.biometrics.face;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.face.FaceManager;
import android.os.UserManager;
import com.android.settings.R;
import com.android.settings.Settings;
@@ -58,6 +59,18 @@ public class FaceStatusUtils {
mContext, BiometricAuthenticator.TYPE_FACE);
}
/**
* Returns the title of face settings entity.
*/
public String getTitle() {
UserManager userManager = mContext.getSystemService(UserManager.class);
if (userManager != null && userManager.isProfile()) {
return mContext.getString(R.string.security_settings_face_profile_preference_title);
} else {
return mContext.getString(R.string.security_settings_face_preference_title);
}
}
/**
* Returns the summary of face settings entity.
*/

View File

@@ -19,6 +19,7 @@ package com.android.settings.biometrics.fingerprint;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.fingerprint.FingerprintManager;
import android.os.UserManager;
import com.android.settings.R;
import com.android.settings.Utils;
@@ -59,6 +60,17 @@ public class FingerprintStatusUtils {
return ParentalControlsUtils.parentConsentRequired(
mContext, BiometricAuthenticator.TYPE_FINGERPRINT);
}
/**
* Returns the title of fingerprint settings entity.
*/
public String getTitle() {
UserManager userManager = mContext.getSystemService(UserManager.class);
if (userManager != null && userManager.isProfile()) {
return mContext.getString(R.string.security_settings_work_fingerprint_preference_title);
} else {
return mContext.getString(R.string.security_settings_fingerprint_preference_title);
}
}
/**
* Returns the summary of fingerprint settings entity.

View File

@@ -17,9 +17,9 @@
package com.android.settings.communal;
import android.content.Context;
import android.os.UserManager;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
/**
@@ -32,14 +32,8 @@ public class CommunalPreferenceController extends BasePreferenceController {
@Override
public int getAvailabilityStatus() {
// TODO(b/257333623): Allow the communal user to be non-SystemUser user in HSUM.
return (mContext.getResources().getBoolean(R.bool.config_show_communal_settings)
&& isSystemUser())
&& Utils.canCurrentUserDream(mContext))
? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
private boolean isSystemUser() {
final UserManager userManager = mContext.getSystemService(UserManager.class);
return userManager != null && userManager.isSystemUser();
}
}

View File

@@ -21,6 +21,7 @@ import static com.android.settings.development.tare.DropdownActivity.POLICY_ALAR
import static com.android.settings.development.tare.DropdownActivity.POLICY_JOB_SCHEDULER;
import android.app.Activity;
import android.app.tare.EconomyManager;
import android.content.Intent;
import android.database.ContentObserver;
import android.net.Uri;
@@ -29,6 +30,7 @@ import android.os.Handler;
import android.os.Looper;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
@@ -41,6 +43,8 @@ import com.android.settings.R;
/** Class for creating the TARE homepage in settings */
public class TareHomePage extends Activity {
private static final String TAG = "TareHomePage";
private Switch mOnSwitch;
private Button mRevButton;
private TextView mAlarmManagerView;
@@ -131,8 +135,6 @@ public class TareHomePage extends Activity {
}
private class ConfigObserver extends ContentObserver {
private static final String KEY_DC_ENABLE_TARE = "enable_tare";
private int mEnableTareSetting;
ConfigObserver(Handler handler) {
@@ -163,7 +165,8 @@ public class TareHomePage extends Activity {
try {
mEnableTareSetting = Integer.parseInt(setting);
} catch (NumberFormatException e) {
mEnableTareSetting = Settings.Global.DEFAULT_ENABLE_TARE;
Log.e(TAG, "Invalid setting value", e);
mEnableTareSetting = EconomyManager.DEFAULT_ENABLE_TARE_MODE;
}
}
final boolean enabled;
@@ -178,9 +181,10 @@ public class TareHomePage extends Activity {
}
private boolean getDefaultEnabledStatus() {
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TARE, KEY_DC_ENABLE_TARE,
Settings.Global.DEFAULT_ENABLE_TARE == SETTING_VALUE_ON);
// Show Shadow Mode as "off" in the UI since it won't be affecting device behavior.
return DeviceConfig.getInt(DeviceConfig.NAMESPACE_TARE,
EconomyManager.KEY_ENABLE_TARE_MODE,
EconomyManager.DEFAULT_ENABLE_TARE_MODE) == EconomyManager.ENABLED_MODE_ON;
}
}
}

View File

@@ -24,6 +24,8 @@ import android.text.TextUtils;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
@@ -44,6 +46,7 @@ public class SimStatusPreferenceController extends BasePreferenceController {
private Fragment mFragment;
private SlotSimStatus mSlotSimStatus;
private Observer<LifecycleOwner> mLifecycleOwnerObserver;
private Observer mSimChangeObserver;
public SimStatusPreferenceController(Context context, String prefKey) {
@@ -112,13 +115,25 @@ public class SimStatusPreferenceController extends BasePreferenceController {
if (mFragment == null) {
return;
}
final int simSlot = getSimSlotIndex();
if (mSimChangeObserver == null) {
mSimChangeObserver = x -> updateStateBySlot(preference, simSlot);
mFragment.getViewLifecycleOwnerLiveData().observeForever(lifecycleOwner -> {
mSlotSimStatus.observe(lifecycleOwner, mSimChangeObserver);
});
} else {
if (mLifecycleOwnerObserver == null) {
final LiveData<LifecycleOwner> dataLifecycleOwner
= mFragment.getViewLifecycleOwnerLiveData();
mLifecycleOwnerObserver = owner -> {
if (owner != null) {
final int simSlot = getSimSlotIndex();
mSimChangeObserver = x -> updateStateBySlot(preference, simSlot);
mSlotSimStatus.observe(owner, mSimChangeObserver);
} else {
if (mSimChangeObserver != null) {
mSlotSimStatus.removeObserver(mSimChangeObserver);
mSimChangeObserver = null;
}
dataLifecycleOwner.removeObserver(mLifecycleOwnerObserver);
}
};
dataLifecycleOwner.observeForever(mLifecycleOwnerObserver);
} else if (mSimChangeObserver != null) {
final int simSlot = getSimSlotIndex();
updateStateBySlot(preference, simSlot);
}
}

View File

@@ -14,9 +14,9 @@
package com.android.settings.display;
import android.content.Context;
import android.os.UserManager;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.dream.DreamSettings;
@@ -39,9 +39,8 @@ public class ScreenSaverPreferenceController extends BasePreferenceController im
com.android.internal.R.bool.config_dreamsSupported);
final boolean dreamsOnlyEnabledForDockUser = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_dreamsOnlyEnabledForDockUser);
final UserManager userManager = mContext.getSystemService(UserManager.class);
// TODO(b/257333623): Allow the Dock User to be non-SystemUser user in HSUM.
return (dreamsSupported && (!dreamsOnlyEnabledForDockUser || userManager.isMainUser()))
return (dreamsSupported && (!dreamsOnlyEnabledForDockUser
|| Utils.canCurrentUserDream(mContext)))
? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}

View File

@@ -25,7 +25,6 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@@ -56,6 +55,8 @@ import com.android.settingslib.widget.SelectorWithWidgetPreference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Power usage detail fragment for each app, this fragment contains
@@ -91,6 +92,8 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
private static final int REQUEST_UNINSTALL = 0;
private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1;
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
@VisibleForTesting
LayoutPreference mHeaderPreference;
@VisibleForTesting
@@ -98,8 +101,6 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
@VisibleForTesting
ApplicationsState.AppEntry mAppEntry;
@VisibleForTesting
BatteryUtils mBatteryUtils;
@VisibleForTesting
BatteryOptimizeUtils mBatteryOptimizeUtils;
@VisibleForTesting
FooterPreference mFooterPreference;
@@ -244,7 +245,6 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
super.onAttach(activity);
mState = ApplicationsState.getInstance(getActivity().getApplication());
mBatteryUtils = BatteryUtils.getInstance(getContext());
}
@Override
@@ -267,12 +267,15 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
initHeader();
mOptimizationMode = mBatteryOptimizeUtils.getAppOptimizationMode();
initPreferenceForTriState(getContext());
final String packageName = mBatteryOptimizeUtils.getPackageName();
FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider()
.action(
getContext(),
SettingsEnums.OPEN_APP_BATTERY_USAGE,
packageName);
mExecutor.execute(() -> {
String packageName =
getLoggingPackageName(getContext(), mBatteryOptimizeUtils.getPackageName());
FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider()
.action(
getContext(),
SettingsEnums.OPEN_APP_BATTERY_USAGE,
packageName);
});
mLogStringBuilder = new StringBuilder("onResume mode = ").append(mOptimizationMode);
}
@@ -444,17 +447,21 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
metricCategory = SettingsEnums.ACTION_APP_BATTERY_USAGE_RESTRICTED;
break;
}
if (metricCategory != 0) {
final String packageName = mBatteryOptimizeUtils.getPackageName();
if (metricCategory == 0) {
return;
}
int finalMetricCategory = metricCategory;
mExecutor.execute(() -> {
String packageName =
getLoggingPackageName(getContext(), mBatteryOptimizeUtils.getPackageName());
FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider()
.action(
/* attribution */ SettingsEnums.OPEN_APP_BATTERY_USAGE,
/* action */ metricCategory,
/* action */ finalMetricCategory,
/* pageId */ SettingsEnums.OPEN_APP_BATTERY_USAGE,
TextUtils.isEmpty(packageName) ? PACKAGE_NAME_NONE : packageName,
packageName,
getArguments().getInt(EXTRA_POWER_USAGE_AMOUNT));
}
});
}
private void onCreateForTriState(String packageName) {
@@ -498,4 +505,9 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
return String.format("%s\n(%s)", usageSummary, slotSummary);
}
}
private static String getLoggingPackageName(Context context, String originalPackingName) {
return BatteryUtils.isAppInstalledFromGooglePlayStore(context, originalPackingName)
? originalPackingName : PACKAGE_NAME_NONE;
}
}

View File

@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -34,6 +35,7 @@ import android.os.SystemClock;
import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Base64;
import android.util.Log;
@@ -83,6 +85,8 @@ public class BatteryUtils {
public static final String BYPASS_DOCK_DEFENDER_ACTION = "battery.dock.defender.bypass";
private static final String GOOGLE_PLAY_STORE_PACKAGE = "com.android.vending";
@Retention(RetentionPolicy.SOURCE)
@IntDef({StatusType.SCREEN_USAGE,
StatusType.FOREGROUND,
@@ -597,6 +601,21 @@ public class BatteryUtils {
return -1L;
}
/** Whether the package is installed from Google Play Store or not */
public static boolean isAppInstalledFromGooglePlayStore(Context context, String packageName) {
if (TextUtils.isEmpty(packageName)) {
return false;
}
InstallSourceInfo installSourceInfo;
try {
installSourceInfo = context.getPackageManager().getInstallSourceInfo(packageName);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
return installSourceInfo != null
&& GOOGLE_PLAY_STORE_PACKAGE.equals(installSourceInfo.getInitiatingPackageName());
}
/** Gets the latest sticky battery intent from the Android system. */
public static Intent getBatteryIntent(Context context) {
return context.registerReceiver(

View File

@@ -18,6 +18,7 @@ package com.android.settings.gestures;
import static android.os.UserHandle.USER_CURRENT;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
@@ -74,6 +75,8 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment i
private static final String KEY_SHOW_A11Y_TUTORIAL_DIALOG = "show_a11y_tutorial_dialog_bool";
private static final int MIN_LARGESCREEN_WIDTH_DP = 600;
private boolean mA11yTutorialDialogShown = false;
private IOverlayManager mOverlayManager;
@@ -112,6 +115,11 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment i
ServiceManager.getService(Context.OVERLAY_SERVICE));
mVideoPreference = new IllustrationPreference(context);
Context windowContext = context.createWindowContext(TYPE_APPLICATION_OVERLAY, null);
if (windowContext.getResources()
.getConfiguration().smallestScreenWidthDp >= MIN_LARGESCREEN_WIDTH_DP) {
mVideoPreference.applyDynamicColor();
}
setIllustrationVideo(mVideoPreference, getDefaultKey());
migrateOverlaySensitivityToSettings(context, mOverlayManager);

View File

@@ -20,64 +20,124 @@ 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.os.UserHandle;
import android.view.InputDevice;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.inputmethod.NewKeyboardSettingsUtils.KeyboardInfo;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
implements InputManager.InputDeviceListener {
private static final String TAG = "NewKeyboardLayoutEnabledLocalesFragment";
private static final String PREF_KEY_ENABLED_LOCALES = "enabled_locales_keyboard_layout";
static final String EXTRA_KEYBOARD_DEVICE_NAME = "extra_keyboard_device_name";
private InputManager mIm;
private InputMethodManager mImm;
private InputDeviceIdentifier mInputDeviceIdentifier;
private int mUserId;
private int mInputDeviceId;
private Context mContext;
private Map<String, KeyboardInfo> mKeyboardLanguageLayouts = new HashMap<>();
@Override
public void onActivityCreated(final Bundle icicle) {
super.onActivityCreated(icicle);
Bundle arguments = getArguments();
final String title = arguments.getString(EXTRA_KEYBOARD_DEVICE_NAME);
mInputDeviceIdentifier = arguments.getParcelable(
KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER);
final String title =
arguments.getString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_DEVICE_NAME);
mInputDeviceIdentifier =
arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER);
getActivity().setTitle(title);
final PreferenceCategory category = findPreference(PREF_KEY_ENABLED_LOCALES);
updateCheckedState();
}
// TODO(b/252816846): Need APIs to get the available keyboards from Inputmanager.
// For example: InputMethodManager.getEnabledInputMethodLocales()
// InputManager.getKeyboardLayoutForLocale()
// Hardcode the default value for demo purpose
String[] keyboardLanguages = {"English (US)", "German (Germany)", "Spanish (Spain)"};
String[] keyboardLayouts = {"English (US)", "German", "Spanish"};
for (int i = 0; i < keyboardLanguages.length; i++) {
private void updateCheckedState() {
PreferenceScreen preferenceScreen = getPreferenceScreen();
preferenceScreen.removeAll();
List<InputMethodInfo> infoList = mImm.getEnabledInputMethodListAsUser(mUserId);
for (InputMethodInfo info : infoList) {
mKeyboardLanguageLayouts.clear();
List<InputMethodSubtype> subtypes =
mImm.getEnabledInputMethodSubtypeList(info, true);
for (InputMethodSubtype subtype : subtypes) {
if (subtype.isSuitableForPhysicalKeyboardLayoutMapping()) {
mapLanguageWithLayout(info, subtype);
}
}
updatePreferenceLayout(preferenceScreen, info);
}
}
private void mapLanguageWithLayout(InputMethodInfo info, InputMethodSubtype subtype) {
KeyboardLayout[] keyboardLayouts = getKeyboardLayouts(info, subtype);
String layout = getKeyboardLayout(info, subtype);
String language = getLanguage(info, subtype);
if (layout != null) {
for (int i = 0; i < keyboardLayouts.length; i++) {
if (keyboardLayouts[i].getDescriptor().equals(layout)) {
KeyboardInfo keyboardInfo = new KeyboardInfo(
language,
keyboardLayouts[i].getLabel(),
info,
subtype);
mKeyboardLanguageLayouts.put(subtype.getLanguageTag(), keyboardInfo);
break;
}
}
} else {
// if there is no auto-selected layout, we should show "Default"
KeyboardInfo keyboardInfo = new KeyboardInfo(
language,
mContext.getString(R.string.keyboard_default_layout),
info,
subtype);
mKeyboardLanguageLayouts.put(subtype.getLanguageTag(), keyboardInfo);
}
}
private void updatePreferenceLayout(PreferenceScreen preferenceScreen, InputMethodInfo info) {
if (mKeyboardLanguageLayouts.isEmpty()) {
return;
}
PreferenceCategory preferenceCategory = new PreferenceCategory(mContext);
preferenceCategory.setTitle(info.loadLabel(mContext.getPackageManager()).toString());
preferenceCategory.setKey(info.getPackageName());
preferenceScreen.addPreference(preferenceCategory);
for (Map.Entry<String, KeyboardInfo> entry : mKeyboardLanguageLayouts.entrySet()) {
final Preference pref = new Preference(mContext);
String key = "keyboard_language_label_" + String.valueOf(i);
String keyboardLanguageTitle = keyboardLanguages[i];
String keyboardLanguageSummary = keyboardLayouts[i];
// TODO: Waiting for new API to use a prefix with special number to setKey
String key = "keyboard_language_" + entry.getKey();
NewKeyboardSettingsUtils.KeyboardInfo keyboardInfo = entry.getValue();
pref.setKey(key);
pref.setTitle(keyboardLanguageTitle);
pref.setSummary(keyboardLanguageSummary);
pref.setTitle(keyboardInfo.getLanguage());
pref.setSummary(keyboardInfo.getLayout());
pref.setOnPreferenceClickListener(
preference -> {
showKeyboardLayoutPicker(
keyboardLanguageTitle,
keyboardLanguageSummary,
mInputDeviceIdentifier);
keyboardInfo.getLanguage(),
keyboardInfo.getLayout(),
mInputDeviceIdentifier,
mUserId,
keyboardInfo.getInputMethodInfo(),
keyboardInfo.getInputMethodSubtype());
return true;
});
category.addPreference(pref);
preferenceCategory.addPreference(pref);
}
}
@@ -96,7 +156,7 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
@Override
public void onInputDeviceChanged(int deviceId) {
if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
// TODO(b/252816846): Need APIs to update the available keyboards.
updateCheckedState();
}
}
@@ -105,7 +165,9 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
super.onCreate(savedInstanceState);
mContext = getContext();
mIm = mContext.getSystemService(InputManager.class);
mImm = mContext.getSystemService(InputMethodManager.class);
mInputDeviceId = -1;
mUserId = UserHandle.myUserId();
}
@Override
@@ -131,7 +193,7 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
@Override
public void onResume() {
super.onResume();
// TODO(b/252816846): Need APIs to get the available keyboards from Inputmanager.
updateCheckedState();
}
@Override
@@ -149,17 +211,50 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
return R.xml.keyboard_settings_enabled_locales_list;
}
private void showKeyboardLayoutPicker(String language, String layout,
InputDeviceIdentifier inputDeviceIdentifier) {
private void showKeyboardLayoutPicker(
String language,
String layout,
InputDeviceIdentifier inputDeviceIdentifier,
int userId,
InputMethodInfo inputMethodInfo,
InputMethodSubtype inputMethodSubtype) {
Bundle arguments = new Bundle();
arguments.putParcelable(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER,
inputDeviceIdentifier);
arguments.putString(NewKeyboardLayoutPickerFragment.EXTRA_TITLE, language);
arguments.putString(NewKeyboardLayoutPickerFragment.EXTRA_KEYBOARD_LAYOUT, layout);
arguments.putParcelable(
NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER, inputDeviceIdentifier);
arguments.putParcelable(
NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_INFO, inputMethodInfo);
arguments.putParcelable(
NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE, inputMethodSubtype);
arguments.putInt(NewKeyboardSettingsUtils.EXTRA_USER_ID, userId);
arguments.putString(NewKeyboardSettingsUtils.EXTRA_TITLE, language);
arguments.putString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_LAYOUT, layout);
new SubSettingLauncher(mContext)
.setSourceMetricsCategory(getMetricsCategory())
.setDestination(NewKeyboardLayoutPickerFragment.class.getName())
.setArguments(arguments)
.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 String getLanguage(InputMethodInfo info, InputMethodSubtype subtype) {
String language;
if (subtype.getLanguageTag().isEmpty()) {
language = subtype.getDisplayName(
mContext,
info.getPackageName(),
info.getServiceInfo().applicationInfo).toString();
} else {
language = Locale.forLanguageTag(subtype.getLanguageTag()).getDisplayName();
}
return language;
}
}

View File

@@ -20,6 +20,8 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.hardware.input.InputDeviceIdentifier;
import android.os.Bundle;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
@@ -28,31 +30,28 @@ public class NewKeyboardLayoutPickerContent extends DashboardFragment {
private static final String TAG = "KeyboardLayoutPicker";
static final String EXTRA_TITLE = "keyboard_layout_picker_title";
static final String EXTRA_KEYBOARD_LAYOUT = "keyboard_layout";
/**
* Intent extra: The input device descriptor of the keyboard whose keyboard
* layout is to be changed.
*/
public static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier";
@Override
public void onAttach(Context context) {
super.onAttach(context);
Bundle arguments = getArguments();
final String title = arguments.getString(EXTRA_TITLE);
final String layout = arguments.getString(EXTRA_KEYBOARD_LAYOUT);
final String title = arguments.getString(NewKeyboardSettingsUtils.EXTRA_TITLE);
final String layout = arguments.getString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_LAYOUT);
final int userId = arguments.getInt(NewKeyboardSettingsUtils.EXTRA_USER_ID);
final InputDeviceIdentifier inputDeviceIdentifier =
arguments.getParcelable(EXTRA_INPUT_DEVICE_IDENTIFIER);
arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER);
final InputMethodInfo inputMethodInfo =
arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_INFO);
final InputMethodSubtype inputMethodSubtype =
arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE);
if (inputDeviceIdentifier == null) {
getActivity().finish();
}
getActivity().setTitle(title);
use(NewKeyboardLayoutPickerController.class).initialize(this /*parent*/,
inputDeviceIdentifier, layout);
use(NewKeyboardLayoutPickerController.class).initialize(this /*parent*/, userId,
inputDeviceIdentifier, inputMethodInfo, inputMethodSubtype, layout);
}
@Override

View File

@@ -21,6 +21,8 @@ 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.InputMethodSubtype;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
@@ -31,7 +33,6 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -42,7 +43,11 @@ public class NewKeyboardLayoutPickerController extends BasePreferenceController
private Fragment mParent;
private int mInputDeviceId;
private int mUserId;
private InputDeviceIdentifier mInputDeviceIdentifier;
private InputMethodInfo mInputMethodInfo;
private InputMethodSubtype mInputMethodSubtype;
private KeyboardLayout[] mKeyboardLayouts;
private PreferenceScreen mScreen;
private String mPreviousSelection;
@@ -55,13 +60,16 @@ public class NewKeyboardLayoutPickerController extends BasePreferenceController
mPreferenceMap = new HashMap<>();
}
public void initialize(Fragment parent, InputDeviceIdentifier inputDeviceIdentifier,
String layout) {
mLayout = layout;
public void initialize(Fragment parent, int userId, InputDeviceIdentifier inputDeviceIdentifier,
InputMethodInfo imeInfo, InputMethodSubtype imeSubtype, String layout) {
mParent = parent;
mUserId = userId;
mInputDeviceIdentifier = inputDeviceIdentifier;
mKeyboardLayouts = mIm.getKeyboardLayoutsForInputDevice(mInputDeviceIdentifier);
Arrays.sort(mKeyboardLayouts);
mInputMethodInfo = imeInfo;
mInputMethodSubtype = imeSubtype;
mLayout = layout;
mKeyboardLayouts = mIm.getKeyboardLayoutListForInputDevice(
inputDeviceIdentifier, userId, imeInfo, imeSubtype);
}
@Override
@@ -102,15 +110,12 @@ public class NewKeyboardLayoutPickerController extends BasePreferenceController
}
final KeyboardLayoutPreference pref = (KeyboardLayoutPreference) preference;
// TODO(b/259530132): Need APIs to update the available keyboards for input device.
// For example:
// inputManager.setCurrentKeyboardLayoutForInputDevice(
// InputDevice..., Userid..., ImeSubType ..., String keyboardLayoutDescriptor)
pref.setCheckMark(true);
if (mPreviousSelection != null && !mPreviousSelection.equals(preference.getKey())) {
KeyboardLayoutPreference preSelectedPref = mScreen.findPreference(mPreviousSelection);
pref.setCheckMark(true);
preSelectedPref.setCheckMark(false);
}
setLayout(pref);
mPreviousSelection = preference.getKey();
return true;
}
@@ -129,13 +134,7 @@ public class NewKeyboardLayoutPickerController extends BasePreferenceController
@Override
public void onInputDeviceChanged(int deviceId) {
if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
updateCheckedState();
}
}
private void updateCheckedState() {
// TODO(b/259530132): Need API to update the keyboard language layout list.
// Do nothing.
}
private void createPreferenceHierarchy() {
@@ -143,14 +142,22 @@ public class NewKeyboardLayoutPickerController extends BasePreferenceController
final KeyboardLayoutPreference pref;
if (mLayout.equals(layout.getLabel())) {
pref = new KeyboardLayoutPreference(mScreen.getContext(), layout.getLabel(), true);
mPreviousSelection = layout.getLabel();
mPreviousSelection = layout.getDescriptor();
} else {
pref = new KeyboardLayoutPreference(mScreen.getContext(), layout.getLabel(), false);
}
// TODO: Waiting for new API to use a prefix with special number to setKey
pref.setKey(layout.getLabel());
pref.setKey(layout.getDescriptor());
mScreen.addPreference(pref);
mPreferenceMap.put(pref, layout);
}
}
private void setLayout(KeyboardLayoutPreference preference) {
mIm.setKeyboardLayoutForInputDevice(
mInputDeviceIdentifier,
mUserId,
mInputMethodInfo,
mInputMethodSubtype,
mPreferenceMap.get(preference).getDescriptor());
}
}

View File

@@ -27,15 +27,6 @@ import com.android.settings.R;
public class NewKeyboardLayoutPickerFragment extends Fragment {
static final String EXTRA_TITLE = "keyboard_layout_picker_title";
static final String EXTRA_KEYBOARD_LAYOUT = "keyboard_layout";
/**
* Intent extra: The input device descriptor of the keyboard whose keyboard
* layout is to be changed.
*/
public static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier";
private ViewGroup mFragmentView;
@Override

View File

@@ -0,0 +1,104 @@
/*
* 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.inputmethod;
import android.content.Context;
import android.provider.Settings;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import java.util.ArrayList;
import java.util.List;
/**
* Utilities of keyboard settings
*/
public class NewKeyboardSettingsUtils {
static final String EXTRA_KEYBOARD_DEVICE_NAME = "extra_keyboard_device_name";
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";
static final String EXTRA_INPUT_METHOD_SUBTYPE = "input_method_subtype";
static InputMethodInfo getActiveIme(Context context, InputMethodManager imm) {
InputMethodInfo activeIme = null;
List<InputMethodInfo> infoList = imm.getEnabledInputMethodList();
String imeId = Settings.Secure.getStringForUser(context.getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD, context.getUserId());
for (InputMethodInfo method : infoList) {
if (method.getId().equals(imeId)) {
activeIme = method;
}
}
return activeIme;
}
static List<String> getSuitableImeLabels(Context context, InputMethodManager imm, int userId) {
List<String> suitableInputMethodInfoLabels = new ArrayList<>();
List<InputMethodInfo> infoList = imm.getEnabledInputMethodListAsUser(userId);
for (InputMethodInfo info : infoList) {
List<InputMethodSubtype> subtypes =
imm.getEnabledInputMethodSubtypeList(info, true);
for (InputMethodSubtype subtype : subtypes) {
if (subtype.isSuitableForPhysicalKeyboardLayoutMapping()) {
suitableInputMethodInfoLabels.add(
info.loadLabel(context.getPackageManager()).toString());
break;
}
}
}
return suitableInputMethodInfoLabels;
}
static class KeyboardInfo {
String mLanguage;
String mLayout;
InputMethodInfo mInputMethodInfo;
InputMethodSubtype mInputMethodSubtype;
KeyboardInfo(
String language,
String layout,
InputMethodInfo inputMethodInfo,
InputMethodSubtype inputMethodSubtype) {
mLanguage = language;
mLayout = layout;
mInputMethodInfo = inputMethodInfo;
mInputMethodSubtype = inputMethodSubtype;
}
String getLanguage() {
return mLanguage;
}
String getLayout() {
return mLayout;
}
InputMethodInfo getInputMethodInfo() {
return mInputMethodInfo;
}
InputMethodSubtype getInputMethodSubtype() {
return mInputMethodSubtype;
}
}
}

View File

@@ -35,6 +35,7 @@ import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.FeatureFlagUtils;
import android.view.InputDevice;
import android.view.inputmethod.InputMethodManager;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceChangeListener;
@@ -54,9 +55,7 @@ import com.android.settingslib.utils.ThreadUtils;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@SearchIndexable
@@ -73,6 +72,7 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
private final ArrayList<HardKeyboardDeviceInfo> mLastHardKeyboards = new ArrayList<>();
private InputManager mIm;
private InputMethodManager mImm;
@NonNull
private PreferenceCategory mKeyboardAssistanceCategory;
@NonNull
@@ -90,6 +90,7 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
mBluetoothAddress = activity.getIntent().getStringExtra(EXTRA_BT_ADDRESS);
addPreferencesFromResource(R.xml.physical_keyboard_settings);
mIm = Preconditions.checkNotNull(activity.getSystemService(InputManager.class));
mImm = Preconditions.checkNotNull(activity.getSystemService(InputMethodManager.class));
mKeyboardAssistanceCategory = Preconditions.checkNotNull(
(PreferenceCategory) findPreference(KEYBOARD_OPTIONS_CATEGORY));
mShowVirtualKeyboardSwitch = Preconditions.checkNotNull(
@@ -194,21 +195,15 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
final Preference pref = new Preference(getPrefContext());
pref.setTitle(hardKeyboardDeviceInfo.mDeviceName);
if (mIsNewKeyboardSettings) {
// TODO(b/252816846): Need InputMethodManager to provide the enabled locales.
// Hardcode Languages for demo until inputMethodManager provides the latest API.
// For example: InputMethodManager.getEnabledInputMethodLocales();
String[] keyboardLanguages =
{"English (US)", "German (Germany)", "Spanish (Spain)"};
String[] keyboardLayouts = {"English (US)", "German", "Spanish"};
Map<String, String> keyboardMap = new HashMap<>();
for (int i = 0; i < keyboardLanguages.length; i++) {
keyboardMap.put(keyboardLanguages[i], keyboardLayouts[i]);
}
if (!keyboardMap.isEmpty()) {
String summary = keyboardMap.get(keyboardLanguages[0]);
List<String> suitableImes = new ArrayList<>();
suitableImes.addAll(
NewKeyboardSettingsUtils.getSuitableImeLabels(
getContext(), mImm, UserHandle.myUserId()));
if (!suitableImes.isEmpty()) {
String summary = suitableImes.get(0);
StringBuilder result = new StringBuilder(summary);
for (int i = 1; i < keyboardLanguages.length; i++) {
result.append(", ").append(keyboardMap.get(keyboardLanguages[i]));
for (int i = 1; i < suitableImes.size(); i++) {
result.append(", ").append(suitableImes.get(i));
}
pref.setSummary(result.toString());
} else {
@@ -245,12 +240,10 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
private void showEnabledLocalesKeyboardLayoutList(String keyboardName,
InputDeviceIdentifier inputDeviceIdentifier) {
// TODO(b/252816846: Need to get enabled locales.
Bundle arguments = new Bundle();
arguments.putParcelable(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER,
arguments.putParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER,
inputDeviceIdentifier);
arguments.putString(NewKeyboardLayoutEnabledLocalesFragment.EXTRA_KEYBOARD_DEVICE_NAME,
keyboardName);
arguments.putString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_DEVICE_NAME, keyboardName);
new SubSettingLauncher(getContext())
.setSourceMetricsCategory(getMetricsCategory())
.setDestination(NewKeyboardLayoutEnabledLocalesFragment.class.getName())

View File

@@ -16,7 +16,6 @@
package com.android.settings.inputmethod;
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
import android.app.Activity;
@@ -97,8 +96,7 @@ public class TrackpadGestureDialogFragment extends BottomSheetDialogFragment {
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
mInflater = (LayoutInflater) mContext.getSystemService(
LAYOUT_INFLATER_SERVICE);
mInflater = mContext.getSystemService(LayoutInflater.class);
View gestureEducationView = mInflater.inflate(R.layout.trackpad_gesture_preview, null);
addViewPager(gestureEducationView);

View File

@@ -18,11 +18,7 @@ package com.android.settings.notification;
import android.content.Context;
import androidx.preference.PreferenceScreen;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.widget.IllustrationPreference;
import com.android.settingslib.widget.LottieColorUtils;
/**
* Controller for the illustration shown for the feature level settings screen for bubbles.
@@ -37,13 +33,4 @@ public class BubbleNotificationIllustrationPreferenceController extends BasePref
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
IllustrationPreference illustrationPreference = screen.findPreference(getPreferenceKey());
illustrationPreference.setOnBindListener(animationView -> {
LottieColorUtils.applyDynamicColors(mContext, animationView);
});
}
}

View File

@@ -27,7 +27,6 @@ import android.safetycenter.SafetyEvent;
import android.safetycenter.SafetySourceData;
import android.safetycenter.SafetySourceStatus;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricNavigationUtils;
import com.android.settings.biometrics.combination.CombinedBiometricStatusUtils;
@@ -63,7 +62,7 @@ public final class BiometricsSafetySource {
final RestrictedLockUtils.EnforcedAdmin disablingAdmin =
combinedBiometricStatusUtils.getDisablingAdmin();
setBiometricSafetySourceData(context,
context.getString(R.string.security_settings_biometric_preference_title),
combinedBiometricStatusUtils.getTitle(),
combinedBiometricStatusUtils.getSummary(),
createPendingIntent(context,
biometricNavigationUtils.getBiometricSettingsIntent(context,
@@ -83,7 +82,7 @@ public final class BiometricsSafetySource {
final RestrictedLockUtils.EnforcedAdmin disablingAdmin =
faceStatusUtils.getDisablingAdmin();
setBiometricSafetySourceData(context,
context.getString(R.string.security_settings_face_preference_title),
faceStatusUtils.getTitle(),
faceStatusUtils.getSummary(),
createPendingIntent(context,
biometricNavigationUtils.getBiometricSettingsIntent(context,
@@ -105,7 +104,7 @@ public final class BiometricsSafetySource {
final RestrictedLockUtils.EnforcedAdmin disablingAdmin =
fingerprintStatusUtils.getDisablingAdmin();
setBiometricSafetySourceData(context,
context.getString(R.string.security_settings_fingerprint_preference_title),
fingerprintStatusUtils.getTitle(),
fingerprintStatusUtils.getSummary(),
createPendingIntent(context,
biometricNavigationUtils.getBiometricSettingsIntent(context,

View File

@@ -23,6 +23,7 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import android.os.UserManager;
import android.safetycenter.SafetyEvent;
import android.safetycenter.SafetySourceData;
import android.safetycenter.SafetySourceIssue;
@@ -56,6 +57,11 @@ public final class LockScreenSafetySource {
return;
}
UserManager userManager = context.getSystemService(UserManager.class);
if (userManager != null && userManager.isProfile()) {
return; // LockScreen source only supports primary profile.
}
if (!screenLockPreferenceDetailsUtils.isAvailable()) {
return;
}
@@ -138,6 +144,12 @@ public final class LockScreenSafetySource {
SET_SCREEN_LOCK_ACTION_ID,
context.getString(R.string.no_screen_lock_issue_action_label),
pendingIntent).build();
// Custom notification deliberately has zero actions
final SafetySourceIssue.Notification customNotification =
new SafetySourceIssue.Notification.Builder(
context.getString(R.string.no_screen_lock_issue_notification_title),
context.getString(R.string.no_screen_lock_issue_notification_text))
.build();
return new SafetySourceIssue.Builder(
NO_SCREEN_LOCK_ISSUE_ID,
context.getString(R.string.no_screen_lock_issue_title),
@@ -145,6 +157,10 @@ public final class LockScreenSafetySource {
SafetySourceData.SEVERITY_LEVEL_RECOMMENDATION,
NO_SCREEN_LOCK_ISSUE_TYPE_ID)
.setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
.addAction(action).build();
.addAction(action)
.setIssueActionability(SafetySourceIssue.ISSUE_ACTIONABILITY_MANUAL)
.setCustomNotification(customNotification)
.setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_DELAYED)
.build();
}
}

View File

@@ -27,8 +27,8 @@ import androidx.compose.ui.res.stringResource
import com.android.settings.R
import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.compose.rememberContext
import com.android.settingslib.spa.framework.util.filterItem
@@ -48,6 +48,7 @@ import kotlinx.coroutines.flow.Flow
object AllAppListPageProvider : SettingsPageProvider {
override val name = "AllAppList"
private val owner = createSettingsPage()
@Composable
override fun Page(arguments: Bundle?) {
@@ -55,7 +56,7 @@ object AllAppListPageProvider : SettingsPageProvider {
}
fun buildInjectEntry() = SettingsEntryBuilder
.createInject(owner = SettingsPage.create(name))
.createInject(owner)
.setSearchDataFn { null }
.setUiLayoutFn {
Preference(object : PreferenceModel {

View File

@@ -27,6 +27,7 @@ import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.LiveData
import com.android.settings.R
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
@@ -36,13 +37,17 @@ private const val TAG = "AppPermissionPreference"
private const val EXTRA_HIDE_INFO_BUTTON = "hideInfoButton"
@Composable
fun AppPermissionPreference(app: ApplicationInfo) {
fun AppPermissionPreference(
app: ApplicationInfo,
summaryLiveData: LiveData<AppPermissionSummaryState> = rememberAppPermissionSummary(app),
) {
val context = LocalContext.current
val summaryLiveData = remember { AppPermissionSummaryLiveData(context, app) }
val summaryState = summaryLiveData.observeAsState(initial = AppPermissionSummaryState(
summary = stringResource(R.string.summary_placeholder),
enabled = false,
))
val summaryState = summaryLiveData.observeAsState(
initial = AppPermissionSummaryState(
summary = stringResource(R.string.summary_placeholder),
enabled = false,
)
)
Preference(
model = remember {
object : PreferenceModel {

View File

@@ -20,6 +20,9 @@ import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager.OnPermissionsChangedListener
import android.icu.text.ListFormatter
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.LiveData
import com.android.settings.R
import com.android.settingslib.applications.PermissionsSummaryHelper
@@ -33,6 +36,12 @@ data class AppPermissionSummaryState(
val enabled: Boolean,
)
@Composable
fun rememberAppPermissionSummary(app: ApplicationInfo): AppPermissionSummaryLiveData {
val context = LocalContext.current
return remember { AppPermissionSummaryLiveData(context, app) }
}
class AppPermissionSummaryLiveData(
private val context: Context,
private val app: ApplicationInfo,

View File

@@ -40,8 +40,8 @@ import com.android.settings.R
import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
import com.android.settings.spa.app.startUninstallActivity
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.compose.rememberContext
import com.android.settingslib.spa.framework.theme.SettingsDimension
@@ -74,6 +74,7 @@ const val BACKGROUND_INSTALL_CONTROL_FLAG = PackageManager.MATCH_ALL.toLong()
object BackgroundInstalledAppsPageProvider : SettingsPageProvider {
override val name = "BackgroundInstalledAppsPage"
private val owner = createSettingsPage()
private var backgroundInstallService = IBackgroundInstallControlService.Stub.asInterface(
ServiceManager.getService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE))
private var featureIsDisabled = featureIsDisabled()
@@ -95,7 +96,7 @@ object BackgroundInstalledAppsPageProvider : SettingsPageProvider {
}
fun buildInjectEntry() = SettingsEntryBuilder
.createInject(owner = SettingsPage.create(name))
.createInject(owner)
.setSearchDataFn { null }
.setUiLayoutFn { EntryItem() }

View File

@@ -22,8 +22,8 @@ import androidx.compose.ui.res.stringResource
import com.android.settings.R
import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
@@ -31,6 +31,7 @@ import com.android.settingslib.spa.widget.scaffold.RegularScaffold
object SpecialAppAccessPageProvider : SettingsPageProvider {
override val name = "SpecialAppAccess"
private val owner = createSettingsPage()
@Composable
override fun Page(arguments: Bundle?) {
@@ -51,10 +52,9 @@ object SpecialAppAccessPageProvider : SettingsPageProvider {
)
}
fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner)
override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
val owner = SettingsPage.create(name, parameter = parameter, arguments = arguments)
return listOf(
AllFilesAccessAppListProvider,
DisplayOverOtherAppsAppListProvider,

View File

@@ -24,6 +24,7 @@ import android.provider.Settings;
import androidx.preference.PreferenceScreen;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import java.util.Arrays;
@@ -67,9 +68,7 @@ public class TimeoutToDockUserPreferenceController extends BasePreferenceControl
return CONDITIONALLY_UNAVAILABLE;
}
// Is currently user zero. Only non user zero can have this setting.
// TODO(b/257333623): Allow the Dock User to be non-SystemUser user in HSUM.
if (UserHandle.myUserId() == UserHandle.USER_SYSTEM) {
if (Utils.canCurrentUserDream(mContext)) {
return DISABLED_FOR_USER;
}

View File

@@ -46,6 +46,7 @@ import android.net.LinkProperties;
import android.net.Network;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.DiskInfo;
import android.os.storage.StorageManager;
@@ -299,4 +300,43 @@ public class UtilsTest {
assertThat(Utils.isSettingsIntelligence(mContext)).isFalse();
}
@Test
public void canCurrentUserDream_isMainUser_returnTrue() {
Context mockContext = mock(Context.class);
UserManager mockUserManager = mock(UserManager.class);
when(mockContext.getSystemService(UserManager.class)).thenReturn(mockUserManager);
// mock MainUser
UserHandle mainUser = new UserHandle(10);
when(mockUserManager.getMainUser()).thenReturn(mainUser);
when(mockUserManager.isUserForeground()).thenReturn(true);
when(mockContext.createContextAsUser(mainUser, 0)).thenReturn(mockContext);
assertThat(Utils.canCurrentUserDream(mockContext)).isTrue();
}
@Test
public void canCurrentUserDream_nullMainUser_returnFalse() {
Context mockContext = mock(Context.class);
UserManager mockUserManager = mock(UserManager.class);
when(mockContext.getSystemService(UserManager.class)).thenReturn(mockUserManager);
when(mockUserManager.getMainUser()).thenReturn(null);
assertThat(Utils.canCurrentUserDream(mockContext)).isFalse();
}
@Test
public void canCurrentUserDream_notMainUser_returnFalse() {
Context mockContext = mock(Context.class);
UserManager mockUserManager = mock(UserManager.class);
when(mockContext.getSystemService(UserManager.class)).thenReturn(mockUserManager);
when(mockUserManager.isUserForeground()).thenReturn(false);
assertThat(Utils.canCurrentUserDream(mockContext)).isFalse();
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.biometrics;
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.verify;
import static org.robolectric.Shadows.shadowOf;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.RemoteException;
import androidx.fragment.app.FragmentActivity;
import com.android.settings.biometrics.face.FaceEnrollIntroduction;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.testutils.shadow.ShadowUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowPackageManager;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
ShadowUtils.class,
ShadowUserManager.class,
ShadowRestrictedLockUtilsInternal.class,
ShadowSensorPrivacyManager.class,
ShadowLockPatternUtils.class
})
public class MultiBiometricEnrollHelperTest {
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@Mock
private FragmentActivity mActivity;
@Mock
private FingerprintManager mFingerprintManager;
@Mock
private FaceManager mFaceManager;
private Context mContext;
@Captor
private ArgumentCaptor<FingerprintManager.GenerateChallengeCallback> mFingerprintCaptor;
private final int mUserId = 10;
private final long mChallenge = 0L;
private final int mSensorId = 0;
private final long mGkPwHandle = 0L;
private MultiBiometricEnrollHelper mMultiBiometricEnrollHelper;
private Intent mFingerprintIntent;
private Intent mFaceIntent;
@Before
public void setUp() throws RemoteException {
mContext = RuntimeEnvironment.application.getApplicationContext();
mFingerprintIntent = new Intent(mContext, FingerprintEnrollIntroduction.class);
mFaceIntent = new Intent(mContext, FaceEnrollIntroduction.class);
mMultiBiometricEnrollHelper = new MultiBiometricEnrollHelper(
mActivity, mUserId, true /* enrollFace */, true /* enrollFingerprint */,
mGkPwHandle, mFingerprintManager, mFaceManager, mFingerprintIntent, mFaceIntent,
(challenge) -> null);
}
@Test
public void launchFaceAndFingerprintEnroll_testFingerprint() {
mMultiBiometricEnrollHelper.startNextStep();
verify(mFingerprintManager).generateChallenge(anyInt(), mFingerprintCaptor.capture());
FingerprintManager.GenerateChallengeCallback generateChallengeCallback =
mFingerprintCaptor.getValue();
generateChallengeCallback.onChallengeGenerated(mSensorId, mUserId, mChallenge);
assertThat(mFingerprintIntent.hasExtra(
MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FINGERPRINT)).isTrue();
assertThat(mFingerprintIntent.getExtra(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID,
-1 /* defaultValue */)).isEqualTo(mSensorId);
assertThat(mFingerprintIntent.getExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE,
-1 /* defaultValue */)).isEqualTo(mChallenge);
assertThat(mFingerprintIntent.getExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
-1 /* defaultValue */)).isEqualTo(mGkPwHandle);
}
@Test
public void launchFaceAndFingerprintEnroll_testFace() {
mMultiBiometricEnrollHelper.startNextStep();
verify(mFingerprintManager).generateChallenge(anyInt(), mFingerprintCaptor.capture());
FingerprintManager.GenerateChallengeCallback fingerprintGenerateChallengeCallback =
mFingerprintCaptor.getValue();
fingerprintGenerateChallengeCallback.onChallengeGenerated(
mSensorId, mUserId, mChallenge);
assertThat(mFaceIntent.getExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
-1 /* defaultValue */)).isEqualTo(mGkPwHandle);
assertThat(mFaceIntent.getIntExtra(Intent.EXTRA_USER_ID, -1 /* defaultValue */))
.isEqualTo(mUserId);
final ShadowPackageManager shadowPackageManager = shadowOf(mContext.getPackageManager());
shadowPackageManager.setSystemFeature(PackageManager.FEATURE_FACE, true);
ShadowUtils.setFaceManager(mFaceManager);
ActivityController.of(new FaceEnrollIntroduction(), mFaceIntent)
.create(mFaceIntent.getExtras()).get();
verify(mFaceManager).generateChallenge(eq(mUserId), any());
}
}

View File

@@ -20,9 +20,8 @@ import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENT
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.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
@@ -38,9 +37,9 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.BatteryStats;
import android.os.Bundle;
import android.os.Process;
import android.os.UserHandle;
@@ -79,6 +78,8 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
import java.util.concurrent.TimeUnit;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowEntityHeaderController.class, ShadowActivityManager.class})
public class AdvancedPowerUsageDetailTest {
@@ -116,12 +117,12 @@ public class AdvancedPowerUsageDetailTest {
@Mock
private PackageManager mPackageManager;
@Mock
private InstallSourceInfo mInstallSourceInfo;
@Mock
private AppOpsManager mAppOpsManager;
@Mock
private LoaderManager mLoaderManager;
@Mock
private BatteryUtils mBatteryUtils;
@Mock
private BatteryOptimizeUtils mBatteryOptimizeUtils;
@Mock
private BackupManager mBackupManager;
@@ -179,7 +180,6 @@ public class AdvancedPowerUsageDetailTest {
mFragment.mHeaderPreference = mHeaderPreference;
mFragment.mState = mState;
mFragment.mBatteryUtils = new BatteryUtils(RuntimeEnvironment.application);
mFragment.mBatteryOptimizeUtils = mBatteryOptimizeUtils;
mFragment.mBackupManager = mBackupManager;
mFragment.mLogStringBuilder = new StringBuilder();
@@ -190,10 +190,6 @@ public class AdvancedPowerUsageDetailTest {
doReturn(mPackageManager).when(mActivity).getPackageManager();
doReturn(mAppOpsManager).when(mTestActivity).getSystemService(Context.APP_OPS_SERVICE);
mBatteryUtils = spy(new BatteryUtils(mContext));
doReturn(FOREGROUND_SERVICE_TIME_US).when(mBatteryUtils).getForegroundServiceTotalTimeUs(
any(BatteryStats.Uid.class), anyLong());
final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
Answer<Void> callable = invocation -> {
@@ -757,34 +753,46 @@ public class AdvancedPowerUsageDetailTest {
}
@Test
public void onPause_optimizationModeChanged_logPreference() {
public void onPause_optimizationModeChanged_logPreference()
throws PackageManager.NameNotFoundException, InterruptedException {
final String packageName = "testPackageName";
final int mode = BatteryOptimizeUtils.MODE_RESTRICTED;
mFragment.mOptimizationMode = mode;
when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(mode);
when(mBatteryOptimizeUtils.getPackageName()).thenReturn(packageName);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(mInstallSourceInfo);
when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn("com.android.vending");
mOptimizePreference.setKey(KEY_PREF_OPTIMIZED);
mFragment.onRadioButtonClicked(mOptimizePreference);
mFragment.onPause();
TimeUnit.SECONDS.sleep(100);
verify(mMetricsFeatureProvider)
.action(
SettingsEnums.OPEN_APP_BATTERY_USAGE,
SettingsEnums.ACTION_APP_BATTERY_USAGE_OPTIMIZED,
SettingsEnums.OPEN_APP_BATTERY_USAGE,
/* package name*/ "none",
packageName,
/* consumed battery */ 0);
}
@Test
public void onPause_optimizationModeIsNotChanged_notInvokeLogging() {
public void onPause_optimizationModeIsNotChanged_notInvokeLogging()
throws PackageManager.NameNotFoundException, InterruptedException {
final int mode = BatteryOptimizeUtils.MODE_OPTIMIZED;
mFragment.mOptimizationMode = mode;
when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(mode);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(mInstallSourceInfo);
when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn("com.android.vending");
mOptimizePreference.setKey(KEY_PREF_OPTIMIZED);
mFragment.onRadioButtonClicked(mOptimizePreference);
mFragment.onPause();
TimeUnit.SECONDS.sleep(100);
verifyNoInteractions(mMetricsFeatureProvider);
}

View File

@@ -0,0 +1,113 @@
/*
* 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.inputmethod;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link TrackpadBottomPreferenceController} */
@RunWith(RobolectricTestRunner.class)
public class TrackpadBottomPreferenceControllerTest {
private static final String PREFERENCE_KEY = "trackpad_bottom_right_tap";
private static final String SETTING_KEY = Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE;
private Context mContext;
private TrackpadBottomPreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mController = new TrackpadBottomPreferenceController(mContext, PREFERENCE_KEY);
}
@Test
public void getAvailabilityStatus_expected() {
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.AVAILABLE);
}
@Test
public void getSliceHighlightMenuRes_expected() {
assertThat(mController.getSliceHighlightMenuRes()).isEqualTo(R.string.menu_key_system);
}
@Test
public void setChecked_true_shouldReturn1() {
mController.setChecked(true);
int result = Settings.System.getIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
0,
UserHandle.USER_CURRENT);
assertThat(result).isEqualTo(1);
}
@Test
public void setChecked_false_shouldReturn0() {
mController.setChecked(false);
int result = Settings.System.getIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
0,
UserHandle.USER_CURRENT);
assertThat(result).isEqualTo(0);
}
@Test
public void isChecked_providerPutInt1_returnTrue() {
Settings.System.putIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
1,
UserHandle.USER_CURRENT);
boolean result = mController.isChecked();
assertThat(result).isTrue();
}
@Test
public void isChecked_providerPutInt0_returnFalse() {
Settings.System.putIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
0,
UserHandle.USER_CURRENT);
boolean result = mController.isChecked();
assertThat(result).isFalse();
}
}

View File

@@ -0,0 +1,109 @@
/*
* 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.inputmethod;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.hardware.input.InputManager;
import android.os.UserHandle;
import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link TrackpadPointerSpeedPreferenceController} */
@RunWith(RobolectricTestRunner.class)
public class TrackpadPointerSpeedPreferenceControllerTest {
private static final String PREFERENCE_KEY = "trackpad_pointer_speed";
private static final String SETTING_KEY = Settings.System.TOUCHPAD_POINTER_SPEED;
private Context mContext;
private TrackpadPointerSpeedPreferenceController mController;
private int mDefaultSpeed;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mController = new TrackpadPointerSpeedPreferenceController(mContext, PREFERENCE_KEY);
mDefaultSpeed = Settings.System.getIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
InputManager.DEFAULT_POINTER_SPEED,
UserHandle.USER_CURRENT);
}
@Test
public void getAvailabilityStatus_expected() {
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.AVAILABLE);
}
@Test
public void getMin_expected() {
assertThat(mController.getMin()).isEqualTo(InputManager.MIN_POINTER_SPEED);
}
@Test
public void getMax_expected() {
assertThat(mController.getMax()).isEqualTo(InputManager.MAX_POINTER_SPEED);
}
@Test
public void getSliderPosition_defaultSpeed_return0() {
int result = mController.getSliderPosition();
assertThat(result).isEqualTo(0);
}
@Test
public void setSliderPosition_speedValue1_shouldReturnTrue() {
int inputSpeed = 1;
boolean result = mController.setSliderPosition(inputSpeed);
assertThat(result).isTrue();
assertThat(mController.getSliderPosition()).isEqualTo(inputSpeed);
}
@Test
public void setSliderPosition_speedValueOverMaxValue_shouldReturnFalse() {
int inputSpeed = InputManager.MAX_POINTER_SPEED + 1;
boolean result = mController.setSliderPosition(inputSpeed);
assertThat(result).isFalse();
assertThat(mController.getSliderPosition()).isEqualTo(mDefaultSpeed);
}
@Test
public void setSliderPosition_speedValueOverMinValue_shouldReturnFalse() {
int inputSpeed = InputManager.MIN_POINTER_SPEED - 1;
boolean result = mController.setSliderPosition(inputSpeed);
assertThat(result).isFalse();
assertThat(mController.getSliderPosition()).isEqualTo(mDefaultSpeed);
}
}

View File

@@ -0,0 +1,114 @@
/*
* 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.inputmethod;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link TrackpadReverseScrollingPreferenceController} */
@RunWith(RobolectricTestRunner.class)
public class TrackpadReverseScrollingPreferenceControllerTest {
private static final String PREFERENCE_KEY = "trackpad_reverse_scrolling";
private static final String SETTING_KEY = Settings.System.TOUCHPAD_NATURAL_SCROLLING;
private Context mContext;
private TrackpadReverseScrollingPreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mController = new TrackpadReverseScrollingPreferenceController(mContext, PREFERENCE_KEY);
}
@Test
public void getAvailabilityStatus_expected() {
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.AVAILABLE);
}
@Test
public void getSliceHighlightMenuRes_expected() {
assertThat(mController.getSliceHighlightMenuRes()).isEqualTo(R.string.menu_key_system);
}
@Test
public void setChecked_true_shouldReturn1() {
mController.setChecked(true);
int result = Settings.System.getIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
0,
UserHandle.USER_CURRENT);
assertThat(result).isEqualTo(1);
}
@Test
public void setChecked_false_shouldReturn0() {
mController.setChecked(false);
int result = Settings.System.getIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
0,
UserHandle.USER_CURRENT);
assertThat(result).isEqualTo(0);
}
@Test
public void isChecked_providerPutInt1_returnTrue() {
Settings.System.putIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
1,
UserHandle.USER_CURRENT);
boolean result = mController.isChecked();
assertThat(result).isTrue();
}
@Test
public void isChecked_providerPutInt0_returnFalse() {
Settings.System.putIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
0,
UserHandle.USER_CURRENT);
boolean result = mController.isChecked();
assertThat(result).isFalse();
}
}

View File

@@ -0,0 +1,113 @@
/*
* 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.inputmethod;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link TrackpadTapToClickPreferenceController} */
@RunWith(RobolectricTestRunner.class)
public class TrackpadTapToClickPreferenceControllerTest {
private static final String PREFERENCE_KEY = "trackpad_tap_to_click";
private static final String SETTING_KEY = Settings.System.TOUCHPAD_TAP_TO_CLICK;
private Context mContext;
private TrackpadTapToClickPreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mController = new TrackpadTapToClickPreferenceController(mContext, PREFERENCE_KEY);
}
@Test
public void getAvailabilityStatus_expected() {
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.AVAILABLE);
}
@Test
public void getSliceHighlightMenuRes_expected() {
assertThat(mController.getSliceHighlightMenuRes()).isEqualTo(R.string.menu_key_system);
}
@Test
public void setChecked_true_shouldReturn1() {
mController.setChecked(true);
int result = Settings.System.getIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
0,
UserHandle.USER_CURRENT);
assertThat(result).isEqualTo(1);
}
@Test
public void setChecked_false_shouldReturn0() {
mController.setChecked(false);
int result = Settings.System.getIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
0,
UserHandle.USER_CURRENT);
assertThat(result).isEqualTo(0);
}
@Test
public void isChecked_providerPutInt1_returnTrue() {
Settings.System.putIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
1,
UserHandle.USER_CURRENT);
boolean result = mController.isChecked();
assertThat(result).isTrue();
}
@Test
public void isChecked_providerPutInt0_returnFalse() {
Settings.System.putIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
0,
UserHandle.USER_CURRENT);
boolean result = mController.isChecked();
assertThat(result).isFalse();
}
}

View File

@@ -32,6 +32,7 @@ import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.fuelgauge.BatteryBackupHelperTest.ShadowUserHandle;
import com.android.settings.testutils.shadow.ShadowSecureSettings;
@@ -106,15 +107,17 @@ public class TimeoutToDockUserPreferenceControllerTest {
}
@Test
public void getAvailabilityStatus_isCurrentlyUserZero_returnDisabledForUser() {
ShadowUserHandle.setUid(UserHandle.USER_SYSTEM);
public void getAvailabilityStatus_isCurrentlyMainUser_returnDisabledForUser() {
when(Utils.canCurrentUserDream(mContext)).thenReturn(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.DISABLED_FOR_USER);
}
@Test
public void getAvailabilityStatus_featureAndMultiUserEnabledAndNonUserZero_returnAvailable() {
public void getAvailabilityStatus_featureAndMultiUserEnabledAndNonMainUser_returnAvailable() {
when(Utils.canCurrentUserDream(mContext)).thenReturn(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}

View File

@@ -0,0 +1,106 @@
/*
* 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.spa.app.appinfo
import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performClick
import androidx.lifecycle.MutableLiveData
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
import com.android.settingslib.spa.testutils.delay
import com.android.settingslib.spaprivileged.model.app.userHandle
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mockito.any
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.eq
import org.mockito.Mockito.verify
import org.mockito.Spy
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
@RunWith(AndroidJUnit4::class)
class AppPermissionPreferenceTest {
@get:Rule
val composeTestRule = createComposeRule()
@get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
@Spy
private val context: Context = ApplicationProvider.getApplicationContext()
@Test
fun title_display() {
setContent()
composeTestRule.onNodeWithText(context.getString(R.string.permissions_label))
.assertIsDisplayed()
}
@Test
fun whenClick_startActivity() {
doNothing().`when`(context).startActivityAsUser(any(), any())
setContent()
composeTestRule.onRoot().performClick()
composeTestRule.delay()
val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
verify(context).startActivityAsUser(intentCaptor.capture(), eq(APP.userHandle))
val intent = intentCaptor.value
assertThat(intent.action).isEqualTo(Intent.ACTION_MANAGE_APP_PERMISSIONS)
assertThat(intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME)).isEqualTo(PACKAGE_NAME)
assertThat(intent.getBooleanExtra(EXTRA_HIDE_INFO_BUTTON, false)).isEqualTo(true)
}
private fun setContent() {
composeTestRule.setContent {
CompositionLocalProvider(LocalContext provides context) {
AppPermissionPreference(
app = APP,
summaryLiveData = MutableLiveData(
AppPermissionSummaryState(summary = SUMMARY, enabled = true)
),
)
}
}
composeTestRule.delay()
}
private companion object {
const val PACKAGE_NAME = "package.name"
const val SUMMARY = "Summary"
private const val EXTRA_HIDE_INFO_BUTTON = "hideInfoButton"
val APP = ApplicationInfo().apply {
packageName = PACKAGE_NAME
}
}
}

View File

@@ -28,6 +28,7 @@ import android.os.UserManager;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.Utils;
import com.android.settings.testutils.ResourcesUtils;
import org.junit.Before;
@@ -41,6 +42,7 @@ public class CommunalPreferenceControllerTest {
@Mock
private UserManager mUserManager;
private Context mContext;
private Resources mResources;
private CommunalPreferenceController mController;
@@ -49,33 +51,33 @@ public class CommunalPreferenceControllerTest {
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
final Context context = spy(ApplicationProvider.getApplicationContext());
mResources = spy(context.getResources());
mContext = spy(ApplicationProvider.getApplicationContext());
mResources = spy(mContext.getResources());
mController = new CommunalPreferenceController(context, PREF_KEY);
mController = new CommunalPreferenceController(mContext, PREF_KEY);
when(context.getResources()).thenReturn(mResources);
when(context.getSystemService(UserManager.class)).thenReturn(mUserManager);
when(mContext.getResources()).thenReturn(mResources);
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
}
@Test
public void isAvailable_communalEnabled_shouldBeTrueForSystemUser() {
public void isAvailable_communalEnabled_shouldBeTrueForDockUser() {
setCommunalEnabled(true);
when(mUserManager.isSystemUser()).thenReturn(true);
when(Utils.canCurrentUserDream(mContext)).thenReturn(true);
assertTrue(mController.isAvailable());
}
@Test
public void isAvailable_communalEnabled_shouldBeFalseForNonSystemUser() {
public void isAvailable_communalEnabled_shouldBeFalseForNonDockUser() {
setCommunalEnabled(true);
when(mUserManager.isSystemUser()).thenReturn(false);
when(Utils.canCurrentUserDream(mContext)).thenReturn(false);
assertFalse(mController.isAvailable());
}
@Test
public void isAvailable_communalDisabled_shouldBeFalseForSystemUser() {
public void isAvailable_communalDisabled_shouldBeFalseForDockUser() {
setCommunalEnabled(false);
when(mUserManager.isSystemUser()).thenReturn(true);
when(Utils.canCurrentUserDream(mContext)).thenReturn(true);
assertFalse(mController.isAvailable());
}