diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 771e3ff29ed..a6a354e1dca 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -4204,7 +4204,6 @@
-
@@ -4826,6 +4825,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/flash_notification_preview_preference.xml b/res/layout/flash_notification_preview_preference.xml
index ecc6f4f01e4..b4be0f62df1 100644
--- a/res/layout/flash_notification_preview_preference.xml
+++ b/res/layout/flash_notification_preview_preference.xml
@@ -34,7 +34,7 @@
android:id="@android:id/title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
- android:layout_gravity="center_vertical"
+ android:layout_gravity="start|center_vertical"
android:paddingVertical="@dimen/settingslib_switch_title_margin"
android:ellipsize="end"
android:textAppearance="?android:attr/textAppearanceListItem"
diff --git a/res/layout/locale_dialog.xml b/res/layout/locale_dialog.xml
index cbdb37eb23e..480c0e293a9 100644
--- a/res/layout/locale_dialog.xml
+++ b/res/layout/locale_dialog.xml
@@ -21,7 +21,9 @@
android:paddingStart="@dimen/admin_details_dialog_padding"
android:paddingEnd="@dimen/admin_details_dialog_padding"
android:paddingBottom="@dimen/admin_details_dialog_padding_bottom"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:layoutDirection="locale"
+ android:textDirection="locale">
+ android:textAppearance="@style/TextAppearance.AdminDialogTitle"
+ android:textAlignment="textStart"/>
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAlignment="textStart"/>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f4e90a0b12f..505aac0f6d5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -410,9 +410,9 @@
Use app default
- Celsius(\u00B0C)
+ Celsius (\u00B0C)
- Fahrenheit(\u00B0F)
+ Fahrenheit (\u00B0F)
Sunday
@@ -427,6 +427,12 @@
Friday
Saturday
+
+ If an app doesn’t support regional preferences, the app will use its default locale settings.
+
+ Learn more about language preferences.
+
+ https://support.google.com/android
{count, plural,
@@ -12041,4 +12047,7 @@
"This app can only be opened in 1 window"
+
+
+ Notetaking
diff --git a/res/xml/regional_preference_main_page.xml b/res/xml/regional_preference_main_page.xml
index de9d3d8e00d..27a1d83818c 100644
--- a/res/xml/regional_preference_main_page.xml
+++ b/res/xml/regional_preference_main_page.xml
@@ -66,4 +66,11 @@
android:value="arg_value_language_select" />
+
+
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index aadca5c4be5..388a510211f 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -986,17 +986,6 @@ public final class Utils extends com.android.settingslib.Utils {
return false;
}
- /**
- * Return the resource id to represent the install status for an app
- */
- @StringRes
- public static int getInstallationStatus(ApplicationInfo info) {
- if ((info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
- return R.string.not_installed;
- }
- return info.enabled ? R.string.installed : R.string.disabled;
- }
-
private static boolean isVolumeValid(VolumeInfo volume) {
return (volume != null) && (volume.getType() == VolumeInfo.TYPE_PRIVATE)
&& volume.isMountedReadable();
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 68fe08e35ee..acc0e7c40fc 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -16,6 +16,7 @@
package com.android.settings.development;
+import static android.provider.Settings.Global.DEVELOPMENT_SETTINGS_ENABLED;
import static android.service.quicksettings.TileService.ACTION_QS_TILE_PREFERENCES;
import android.app.Activity;
@@ -27,12 +28,18 @@ import android.bluetooth.BluetoothCodecStatus;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.os.SystemProperties;
import android.os.UserManager;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
@@ -173,10 +180,47 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
}
};
+ private final Uri mDevelopEnabled = Settings.Global.getUriFor(DEVELOPMENT_SETTINGS_ENABLED);
+ private final ContentObserver mDeveloperSettingsObserver = new ContentObserver(new Handler(
+ Looper.getMainLooper())) {
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ super.onChange(selfChange, uri);
+ final boolean developmentEnabledState =
+ DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(getContext());
+ final boolean switchState = mSwitchBar.isChecked();
+
+ // when developer options is enabled, but it is disabled by other privilege apps like:
+ // adb command, we should disable all items and finish the activity.
+ if (developmentEnabledState != switchState) {
+ if (developmentEnabledState) {
+ return;
+ }
+ disableDeveloperOptions();
+ getActivity().runOnUiThread(() -> finishFragment());
+ }
+ }
+ };
+
public DevelopmentSettingsDashboardFragment() {
super(UserManager.DISALLOW_DEBUGGING_FEATURES);
}
+ @Override
+ public void onStart() {
+ super.onStart();
+ final ContentResolver cr = getContext().getContentResolver();
+ cr.registerContentObserver(mDevelopEnabled, false, mDeveloperSettingsObserver);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ final ContentResolver cr = getContext().getContentResolver();
+ cr.unregisterContentObserver(mDeveloperSettingsObserver);
+ }
+
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
diff --git a/src/com/android/settings/inputmethod/ModifierKeysPickerDialogFragment.java b/src/com/android/settings/inputmethod/ModifierKeysPickerDialogFragment.java
index f1d7e7f28ec..14578afbaa7 100644
--- a/src/com/android/settings/inputmethod/ModifierKeysPickerDialogFragment.java
+++ b/src/com/android/settings/inputmethod/ModifierKeysPickerDialogFragment.java
@@ -18,6 +18,7 @@ package com.android.settings.inputmethod;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
@@ -52,11 +53,13 @@ import java.util.Map;
public class ModifierKeysPickerDialogFragment extends DialogFragment {
+ static final String DEFAULT_KEY = "default_key";
+ static final String SELECTION_KEY = "delection_key";
+
private Preference mPreference;
private String mKeyDefaultName;
private String mKeyFocus;
- private Context mContext;
- private InputManager mIm;
+ private Activity mActivity;
private List mRemappableKeyList =
new ArrayList<>(Arrays.asList(
@@ -67,36 +70,41 @@ public class ModifierKeysPickerDialogFragment extends DialogFragment {
private Map mRemappableKeyMap = new HashMap<>();
- public ModifierKeysPickerDialogFragment() {
- }
+ public ModifierKeysPickerDialogFragment() {}
- public ModifierKeysPickerDialogFragment(Preference preference, InputManager inputManager) {
- mPreference = preference;
- mKeyDefaultName = preference.getTitle().toString();
- mKeyFocus = preference.getSummary().toString();
- mIm = inputManager;
+ @Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ savedInstanceState.putString(SELECTION_KEY, mKeyFocus);
+ super.onSaveInstanceState(savedInstanceState);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
super.onCreateDialog(savedInstanceState);
- mContext = getActivity();
+
+ mActivity = getActivity();
+ InputManager inputManager = mActivity.getSystemService(InputManager.class);
+ mKeyDefaultName = getArguments().getString(DEFAULT_KEY);
+ mKeyFocus = getArguments().getString(SELECTION_KEY);
+ if (savedInstanceState != null) {
+ mKeyFocus = savedInstanceState.getString(SELECTION_KEY);
+ }
List modifierKeys = new ArrayList(Arrays.asList(
- mContext.getString(R.string.modifier_keys_caps_lock),
- mContext.getString(R.string.modifier_keys_ctrl),
- mContext.getString(R.string.modifier_keys_meta),
- mContext.getString(R.string.modifier_keys_alt)));
+ mActivity.getString(R.string.modifier_keys_caps_lock),
+ mActivity.getString(R.string.modifier_keys_ctrl),
+ mActivity.getString(R.string.modifier_keys_meta),
+ mActivity.getString(R.string.modifier_keys_alt)));
for (int i = 0; i < modifierKeys.size(); i++) {
mRemappableKeyMap.put(modifierKeys.get(i), mRemappableKeyList.get(i));
}
View dialoglayout =
- LayoutInflater.from(mContext).inflate(R.layout.modifier_key_picker_dialog, null);
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
+ LayoutInflater.from(mActivity).inflate(R.layout.modifier_key_picker_dialog, null);
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mActivity);
dialogBuilder.setView(dialoglayout);
TextView summary = dialoglayout.findViewById(R.id.modifier_key_picker_summary);
- CharSequence summaryText = mContext.getString(
+ CharSequence summaryText = mActivity.getString(
R.string.modifier_keys_picker_summary, mKeyDefaultName);
summary.setText(summaryText);
@@ -119,14 +127,14 @@ public class ModifierKeysPickerDialogFragment extends DialogFragment {
Spannable itemSummary;
if (selectedItem.equals(mKeyDefaultName)) {
itemSummary = new SpannableString(
- mContext.getString(R.string.modifier_keys_default_summary));
+ mActivity.getString(R.string.modifier_keys_default_summary));
itemSummary.setSpan(
new ForegroundColorSpan(getColorOfTextColorSecondary()),
0, itemSummary.length(), 0);
// Set keys to default.
int[] keys = mRemappableKeyMap.get(mKeyDefaultName);
for (int i = 0; i < keys.length; i++) {
- mIm.remapModifierKey(keys[i], keys[i]);
+ inputManager.remapModifierKey(keys[i], keys[i]);
}
} else {
itemSummary = new SpannableString(selectedItem);
@@ -136,29 +144,29 @@ public class ModifierKeysPickerDialogFragment extends DialogFragment {
int[] fromKeys = mRemappableKeyMap.get(mKeyDefaultName);
int[] toKeys = mRemappableKeyMap.get(selectedItem);
// CAPS_LOCK only one key, so always choose the left key for remapping.
- if (isKeyCapsLock(mContext, mKeyDefaultName)) {
- mIm.remapModifierKey(fromKeys[0], toKeys[0]);
+ if (isKeyCapsLock(mActivity, mKeyDefaultName)) {
+ inputManager.remapModifierKey(fromKeys[0], toKeys[0]);
}
// Remap KEY_LEFT and KEY_RIGHT to CAPS_LOCK.
- if (!isKeyCapsLock(mContext, mKeyDefaultName)
- && isKeyCapsLock(mContext, selectedItem)) {
- mIm.remapModifierKey(fromKeys[0], toKeys[0]);
- mIm.remapModifierKey(fromKeys[1], toKeys[0]);
+ if (!isKeyCapsLock(mActivity, mKeyDefaultName)
+ && isKeyCapsLock(mActivity, selectedItem)) {
+ inputManager.remapModifierKey(fromKeys[0], toKeys[0]);
+ inputManager.remapModifierKey(fromKeys[1], toKeys[0]);
}
// Auto handle left and right keys remapping.
- if (!isKeyCapsLock(mContext, mKeyDefaultName)
- && !isKeyCapsLock(mContext, selectedItem)) {
- mIm.remapModifierKey(fromKeys[0], toKeys[0]);
- mIm.remapModifierKey(fromKeys[1], toKeys[1]);
+ if (!isKeyCapsLock(mActivity, mKeyDefaultName)
+ && !isKeyCapsLock(mActivity, selectedItem)) {
+ inputManager.remapModifierKey(fromKeys[0], toKeys[0]);
+ inputManager.remapModifierKey(fromKeys[1], toKeys[1]);
}
}
- mPreference.setSummary(itemSummary);
- modifierKeyDialog.dismiss();
+ dismiss();
+ mActivity.recreate();
});
Button cancelButton = dialoglayout.findViewById(R.id.modifier_key_cancel_button);
cancelButton.setOnClickListener(v -> {
- modifierKeyDialog.dismiss();
+ dismiss();
});
final Window window = modifierKeyDialog.getWindow();
@@ -207,16 +215,17 @@ public class ModifierKeysPickerDialogFragment extends DialogFragment {
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
if (view == null) {
- view = LayoutInflater.from(mContext).inflate(R.layout.modifier_key_item, null);
+ view = LayoutInflater.from(mActivity).inflate(R.layout.modifier_key_item, null);
}
TextView textView = view.findViewById(R.id.modifier_key_text);
ImageView checkIcon = view.findViewById(R.id.modifier_key_check_icon);
textView.setText(mList.get(i));
if (mCurrentItem == i) {
+ mKeyFocus = mList.get(i);
textView.setTextColor(getColorOfColorAccentPrimaryVariant());
checkIcon.setImageAlpha(255);
view.setBackground(
- mContext.getDrawable(R.drawable.modifier_key_lisetview_background));
+ mActivity.getDrawable(R.drawable.modifier_key_lisetview_background));
} else {
textView.setTextColor(getColorOfTextColorPrimary());
checkIcon.setImageAlpha(0);
@@ -235,15 +244,15 @@ public class ModifierKeysPickerDialogFragment extends DialogFragment {
}
private int getColorOfTextColorPrimary() {
- return Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
+ return Utils.getColorAttrDefaultColor(mActivity, android.R.attr.textColorPrimary);
}
private int getColorOfTextColorSecondary() {
- return Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorSecondary);
+ return Utils.getColorAttrDefaultColor(mActivity, android.R.attr.textColorSecondary);
}
private int getColorOfColorAccentPrimaryVariant() {
return Utils.getColorAttrDefaultColor(
- mContext, com.android.internal.R.attr.materialColorPrimaryContainer);
+ mActivity, com.android.internal.R.attr.materialColorPrimaryContainer);
}
}
diff --git a/src/com/android/settings/inputmethod/ModifierKeysPreferenceController.java b/src/com/android/settings/inputmethod/ModifierKeysPreferenceController.java
index 780a980917a..91caf2937f5 100644
--- a/src/com/android/settings/inputmethod/ModifierKeysPreferenceController.java
+++ b/src/com/android/settings/inputmethod/ModifierKeysPreferenceController.java
@@ -18,12 +18,12 @@ package com.android.settings.inputmethod;
import android.content.Context;
import android.hardware.input.InputManager;
+import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.view.KeyEvent;
-import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
@@ -41,8 +41,8 @@ import java.util.Objects;
public class ModifierKeysPreferenceController extends BasePreferenceController {
- private static String KEY_TAG = "modifier_keys_dialog_tag";
- private static String KEY_RESTORE_PREFERENCE = "modifier_keys_restore";
+ private static final String KEY_TAG = "modifier_keys_dialog_tag";
+ private static final String KEY_RESTORE_PREFERENCE = "modifier_keys_restore";
private static final String KEY_PREFERENCE_CAPS_LOCK = "modifier_keys_caps_lock";
private static final String KEY_PREFERENCE_CTRL = "modifier_keys_ctrl";
@@ -52,6 +52,7 @@ public class ModifierKeysPreferenceController extends BasePreferenceController {
private Fragment mParent;
private FragmentManager mFragmentManager;
private final InputManager mIm;
+ private PreferenceScreen mScreen;
private final List mRemappableKeys = new ArrayList<>(
Arrays.asList(
@@ -82,40 +83,39 @@ public class ModifierKeysPreferenceController extends BasePreferenceController {
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
-
if (mParent == null) {
return;
}
+ mScreen = screen;
+ refreshUi();
+ }
+ private void refreshUi() {
for (Map.Entry entry : mIm.getModifierKeyRemapping().entrySet()) {
int fromKey = entry.getKey();
int toKey = entry.getValue();
int index = mRemappableKeys.indexOf(toKey);
if (isCtrl(fromKey) && mRemappableKeys.contains(toKey)) {
- Preference preference = screen.findPreference(KEY_PREFERENCE_CTRL);
+ Preference preference = mScreen.findPreference(KEY_PREFERENCE_CTRL);
preference.setSummary(changeSummaryColor(mKeyNames[index]));
}
if (isMeta(fromKey) && mRemappableKeys.contains(toKey)) {
- Preference preference = screen.findPreference(KEY_PREFERENCE_META);
+ Preference preference = mScreen.findPreference(KEY_PREFERENCE_META);
preference.setSummary(changeSummaryColor(mKeyNames[index]));
}
if (isAlt(fromKey) && mRemappableKeys.contains(toKey)) {
- Preference preference = screen.findPreference(KEY_PREFERENCE_ALT);
+ Preference preference = mScreen.findPreference(KEY_PREFERENCE_ALT);
preference.setSummary(changeSummaryColor(mKeyNames[index]));
}
if (isCapLock(fromKey) && mRemappableKeys.contains(toKey)) {
- Preference preference = screen.findPreference(KEY_PREFERENCE_CAPS_LOCK);
+ Preference preference = mScreen.findPreference(KEY_PREFERENCE_CAPS_LOCK);
preference.setSummary(changeSummaryColor(mKeyNames[index]));
}
}
-
- // The dialog screen depends on the previous selected key's fragment.
- // In the rotation scenario, we should remove the previous dialog screen first.
- clearPreviousDialog();
}
@Override
@@ -133,19 +133,18 @@ public class ModifierKeysPreferenceController extends BasePreferenceController {
}
private void showModifierKeysDialog(Preference preference) {
- ModifierKeysPickerDialogFragment fragment =
- new ModifierKeysPickerDialogFragment(preference, mIm);
- fragment.setTargetFragment(mParent, 0);
- fragment.show(mFragmentManager, KEY_TAG);
- }
-
- private void clearPreviousDialog() {
mFragmentManager = mParent.getFragmentManager();
- DialogFragment preKeysDialogFragment =
- (DialogFragment) mFragmentManager.findFragmentByTag(KEY_TAG);
- if (preKeysDialogFragment != null) {
- preKeysDialogFragment.dismiss();
- }
+ ModifierKeysPickerDialogFragment fragment = new ModifierKeysPickerDialogFragment();
+ fragment.setTargetFragment(mParent, 0);
+ Bundle bundle = new Bundle();
+ bundle.putString(
+ ModifierKeysPickerDialogFragment.DEFAULT_KEY,
+ preference.getTitle().toString());
+ bundle.putString(
+ ModifierKeysPickerDialogFragment.SELECTION_KEY,
+ preference.getSummary().toString());
+ fragment.setArguments(bundle);
+ fragment.show(mFragmentManager, KEY_TAG);
}
private Spannable changeSummaryColor(String summary) {
diff --git a/src/com/android/settings/inputmethod/ModifierKeysResetDialogFragment.java b/src/com/android/settings/inputmethod/ModifierKeysResetDialogFragment.java
index 4ca5ddde6c8..755e9dddedf 100644
--- a/src/com/android/settings/inputmethod/ModifierKeysResetDialogFragment.java
+++ b/src/com/android/settings/inputmethod/ModifierKeysResetDialogFragment.java
@@ -18,25 +18,19 @@ package com.android.settings.inputmethod;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
-import android.content.Context;
import android.hardware.input.InputManager;
import android.os.Bundle;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import androidx.fragment.app.DialogFragment;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
import com.android.settings.R;
-import com.android.settingslib.Utils;
public class ModifierKeysResetDialogFragment extends DialogFragment {
private static final String MODIFIER_KEYS_CAPS_LOCK = "modifier_keys_caps_lock";
@@ -44,41 +38,36 @@ public class ModifierKeysResetDialogFragment extends DialogFragment {
private static final String MODIFIER_KEYS_META = "modifier_keys_meta";
private static final String MODIFIER_KEYS_ALT = "modifier_keys_alt";
- private PreferenceScreen mScreen;
- private InputManager mIm;
private String[] mKeys = {
MODIFIER_KEYS_CAPS_LOCK,
MODIFIER_KEYS_CTRL,
MODIFIER_KEYS_META,
MODIFIER_KEYS_ALT};
- public ModifierKeysResetDialogFragment() {
- }
-
- public ModifierKeysResetDialogFragment(PreferenceScreen screen, InputManager inputManager) {
- mScreen = screen;
- mIm = inputManager;
- }
+ public ModifierKeysResetDialogFragment() {}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
super.onCreateDialog(savedInstanceState);
- Context mContext = getActivity();
+
+ Activity activity = getActivity();
+ InputManager inputManager = activity.getSystemService(InputManager.class);
View dialoglayout =
- LayoutInflater.from(mContext).inflate(R.layout.modifier_key_reset_dialog, null);
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
+ LayoutInflater.from(activity).inflate(R.layout.modifier_key_reset_dialog, null);
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity);
dialogBuilder.setView(dialoglayout);
AlertDialog modifierKeyResetDialog = dialogBuilder.create();
Button restoreButton = dialoglayout.findViewById(R.id.modifier_key_reset_restore_button);
restoreButton.setOnClickListener(v -> {
- resetToDefault();
- modifierKeyResetDialog.dismiss();
+ inputManager.clearAllModifierKeyRemappings();
+ dismiss();
+ activity.recreate();
});
Button cancelButton = dialoglayout.findViewById(R.id.modifier_key_reset_cancel_button);
cancelButton.setOnClickListener(v -> {
- modifierKeyResetDialog.dismiss();
+ dismiss();
});
final Window window = modifierKeyResetDialog.getWindow();
@@ -86,25 +75,4 @@ public class ModifierKeysResetDialogFragment extends DialogFragment {
return modifierKeyResetDialog;
}
-
- private void resetToDefault() {
- Context mContext = getActivity();
- for (int i = 0; i < mKeys.length; i++) {
- Preference preference = mScreen.findPreference(mKeys[i]);
- Spannable title = new SpannableString(
- mContext.getString(R.string.modifier_keys_default_summary));
- title.setSpan(
- new ForegroundColorSpan(getColorOfTextColorSecondary()),
- 0, title.length(), 0);
- preference.setSummary(title);
- }
-
- if (mIm != null) {
- mIm.clearAllModifierKeyRemappings();
- }
- }
-
- private int getColorOfTextColorSecondary() {
- return Utils.getColorAttrDefaultColor(getActivity(), android.R.attr.textColorSecondary);
- }
}
diff --git a/src/com/android/settings/inputmethod/ModifierKeysRestorePreferenceController.java b/src/com/android/settings/inputmethod/ModifierKeysRestorePreferenceController.java
index 4e72fbdff83..3171487382e 100644
--- a/src/com/android/settings/inputmethod/ModifierKeysRestorePreferenceController.java
+++ b/src/com/android/settings/inputmethod/ModifierKeysRestorePreferenceController.java
@@ -17,12 +17,10 @@
package com.android.settings.inputmethod;
import android.content.Context;
-import android.hardware.input.InputManager;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
-import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
@@ -34,16 +32,14 @@ import com.android.settingslib.Utils;
public class ModifierKeysRestorePreferenceController extends BasePreferenceController {
- private static String KEY_TAG = "modifier_keys_dialog_tag";
+ private static final String KEY_TAG = "modifier_keys_restore_dialog_tag";
private Fragment mParent;
private FragmentManager mFragmentManager;
private PreferenceScreen mScreen;
- private final InputManager mIm;
public ModifierKeysRestorePreferenceController(Context context, String key) {
super(context, key);
- mIm = context.getSystemService(InputManager.class);
}
public void setFragment(Fragment parent) {
@@ -57,9 +53,6 @@ public class ModifierKeysRestorePreferenceController extends BasePreferenceContr
return;
}
mScreen = screen;
- // The dialog screen depends on the previous selected key's fragment.
- // In the rotation scenario, we should remove the previous dialog first.
- clearPreviousDialog();
setResetKeyColor();
}
@@ -78,8 +71,8 @@ public class ModifierKeysRestorePreferenceController extends BasePreferenceContr
}
private void showResetDialog() {
- ModifierKeysResetDialogFragment fragment =
- new ModifierKeysResetDialogFragment(mScreen, mIm);
+ mFragmentManager = mParent.getFragmentManager();
+ ModifierKeysResetDialogFragment fragment = new ModifierKeysResetDialogFragment();
fragment.setTargetFragment(mParent, 0);
fragment.show(mFragmentManager, KEY_TAG);
}
@@ -98,13 +91,4 @@ public class ModifierKeysRestorePreferenceController extends BasePreferenceContr
return Utils.getColorAttrDefaultColor(
mParent.getActivity(), com.android.internal.R.attr.materialColorPrimaryContainer);
}
-
- private void clearPreviousDialog() {
- mFragmentManager = mParent.getFragmentManager();
- DialogFragment preResetDialogFragment =
- (DialogFragment) mFragmentManager.findFragmentByTag(KEY_TAG);
- if (preResetDialogFragment != null) {
- preResetDialogFragment.dismiss();
- }
- }
}
diff --git a/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java b/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java
index 05c740139cc..a639c9d297a 100644
--- a/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java
+++ b/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java
@@ -17,6 +17,8 @@
package com.android.settings.localepicker;
import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceScreen;
@@ -65,10 +67,14 @@ public class LocaleHelperPreferenceController extends AbstractPreferenceControll
}
private void openLocaleLearnMoreLink() {
- mContext.startActivity(
- HelpUtils.getHelpIntent(
- mContext,
- mContext.getString(R.string.link_locale_picker_footer_learn_more),
- /*backupContext=*/""));
+ Intent intent = HelpUtils.getHelpIntent(
+ mContext,
+ mContext.getString(R.string.link_locale_picker_footer_learn_more),
+ mContext.getClass().getName());
+ if (intent != null) {
+ mContext.startActivity(intent);
+ } else {
+ Log.w(TAG, "HelpIntent is null");
+ }
}
}
diff --git a/src/com/android/settings/notetask/shortcut/CreateNoteTaskShortcutActivity.kt b/src/com/android/settings/notetask/shortcut/CreateNoteTaskShortcutActivity.kt
new file mode 100644
index 00000000000..b9846226df6
--- /dev/null
+++ b/src/com/android/settings/notetask/shortcut/CreateNoteTaskShortcutActivity.kt
@@ -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.notetask.shortcut
+
+import android.app.Activity
+import android.app.role.RoleManager
+import android.app.role.RoleManager.ROLE_NOTES
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.ShortcutInfo
+import android.content.pm.ShortcutManager
+import android.graphics.drawable.Icon
+import android.os.Bundle
+import android.os.PersistableBundle
+import android.os.UserHandle
+import androidx.activity.ComponentActivity
+import androidx.core.content.getSystemService
+import com.android.settings.R
+
+/**
+ * Activity responsible for create a shortcut for notes action. If the shortcut is enabled, a new
+ * shortcut will appear in the widget picker. If the shortcut is selected, the Activity here will be
+ * launched, creating a new shortcut for [CreateNoteTaskShortcutActivity], and will finish.
+ *
+ * @see Creating
+ * a custom shortcut activity
+ */
+internal class CreateNoteTaskShortcutActivity : ComponentActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ val roleManager = requireNotNull(getSystemService())
+ val shortcutManager = requireNotNull(getSystemService())
+
+ super.onCreate(savedInstanceState)
+
+ val shortcutInfo = roleManager.createNoteShortcutInfoAsUser(context = this, user)
+ val shortcutIntent = shortcutManager.createShortcutResultIntent(shortcutInfo)
+ setResult(Activity.RESULT_OK, shortcutIntent)
+
+ finish()
+ }
+
+ private companion object {
+
+ private const val SHORTCUT_ID = "note_task_shortcut_id"
+ private const val EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE =
+ "extra_shortcut_badge_override_package"
+ private const val ACTION_LAUNCH_NOTE_TASK = "com.android.systemui.action.LAUNCH_NOTE_TASK"
+
+ private fun RoleManager.createNoteShortcutInfoAsUser(
+ context: Context,
+ user: UserHandle,
+ ): ShortcutInfo? {
+ val systemUiComponent = context.getSystemUiComponent() ?: return null
+
+ val extras = PersistableBundle()
+ getDefaultRoleHolderAsUser(ROLE_NOTES, user)?.let { packageName ->
+ // Set custom app badge using the icon from ROLES_NOTES default app.
+ extras.putString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE, packageName)
+ }
+
+ val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
+
+ val intent = Intent(ACTION_LAUNCH_NOTE_TASK).apply {
+ setPackage(systemUiComponent.packageName)
+ }
+
+ return ShortcutInfo.Builder(context, SHORTCUT_ID)
+ .setIntent(intent)
+ .setShortLabel(context.getString(R.string.note_task_button_label))
+ .setLongLived(true)
+ .setIcon(icon)
+ .setExtras(extras)
+ .build()
+ }
+
+ private fun RoleManager.getDefaultRoleHolderAsUser(
+ role: String,
+ user: UserHandle,
+ ): String? = getRoleHoldersAsUser(role, user).firstOrNull()
+
+ private fun Context.getSystemUiComponent(): ComponentName? {
+ val flattenName = getString(
+ com.android.internal.R.string.config_systemUIServiceComponent)
+ check(flattenName.isNotEmpty()) {
+ "No 'com.android.internal.R.string.config_systemUIServiceComponent' resource"
+ }
+ return try {
+ ComponentName.unflattenFromString(flattenName)
+ } catch (e: RuntimeException) {
+ val message = "Invalid component name defined by 'com.android.internal.R.string." +
+ "config_systemUIServiceComponent' resource: $flattenName"
+ throw IllegalStateException(message, e)
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/regionalpreferences/RegionalFooterPreferenceController.java b/src/com/android/settings/regionalpreferences/RegionalFooterPreferenceController.java
new file mode 100644
index 00000000000..6ba9d187032
--- /dev/null
+++ b/src/com/android/settings/regionalpreferences/RegionalFooterPreferenceController.java
@@ -0,0 +1,74 @@
+/**
+ * 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.regionalpreferences;
+
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.HelpUtils;
+import com.android.settingslib.widget.FooterPreference;
+
+/**
+ * Preference controller for regional preference footer.
+ */
+public class RegionalFooterPreferenceController extends BasePreferenceController {
+
+ private static final String TAG = "RegionalFooterPreferenceController";
+
+ public RegionalFooterPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE_UNSEARCHABLE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ FooterPreference footerPreference = screen.findPreference(getPreferenceKey());
+ setupFooterPreference(footerPreference);
+ }
+
+ @VisibleForTesting
+ void setupFooterPreference(FooterPreference footerPreference) {
+ if (footerPreference != null) {
+ footerPreference.setLearnMoreAction(v -> openLocaleLearnMoreLink());
+ footerPreference.setLearnMoreText(mContext.getString(
+ R.string.desc_regional_pref_footer_learn_more));
+ }
+ }
+
+ private void openLocaleLearnMoreLink() {
+ Intent intent = HelpUtils.getHelpIntent(
+ mContext,
+ mContext.getString(R.string.regional_pref_footer_learn_more_link),
+ mContext.getClass().getName());
+ if (intent != null) {
+ mContext.startActivity(intent);
+ } else {
+ Log.w(TAG, "HelpIntent is null");
+ }
+ }
+}
diff --git a/src/com/android/settings/spa/app/AllAppList.kt b/src/com/android/settings/spa/app/AllAppList.kt
index d3572996402..8bd18844998 100644
--- a/src/com/android/settings/spa/app/AllAppList.kt
+++ b/src/com/android/settings/spa/app/AllAppList.kt
@@ -38,6 +38,7 @@ import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.model.app.AppListModel
import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.android.settingslib.spaprivileged.model.app.installed
import com.android.settingslib.spaprivileged.template.app.AppList
import com.android.settingslib.spaprivileged.template.app.AppListInput
import com.android.settingslib.spaprivileged.template.app.AppListItem
@@ -75,6 +76,7 @@ fun AllAppListPage(
title = stringResource(R.string.all_apps),
listModel = rememberContext(::AllAppListModel),
showInstantApps = true,
+ matchAnyUserForAdmin = true,
moreOptions = { ResetAppPreferences(resetAppDialogPresenter::open) },
appList = appList,
)
@@ -133,8 +135,13 @@ class AllAppListModel(
return remember {
derivedStateOf {
storageSummary.value +
- when (isDisabled(record)) {
- true -> System.lineSeparator() + context.getString(R.string.disabled)
+ when {
+ !record.app.installed -> {
+ System.lineSeparator() + context.getString(R.string.not_installed)
+ }
+ isDisabled(record) -> {
+ System.lineSeparator() + context.getString(R.string.disabled)
+ }
else -> ""
}
}
diff --git a/src/com/android/settings/spa/app/appinfo/AppNotificationPreference.kt b/src/com/android/settings/spa/app/appinfo/AppNotificationPreference.kt
index e1792a915ba..490a98c795e 100644
--- a/src/com/android/settings/spa/app/appinfo/AppNotificationPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppNotificationPreference.kt
@@ -30,8 +30,10 @@ import com.android.settings.notification.app.AppNotificationSettings
import com.android.settings.spa.notification.AppNotificationRepository
import com.android.settings.spa.notification.IAppNotificationRepository
import com.android.settingslib.spa.framework.compose.rememberContext
+import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spaprivileged.model.app.installed
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
@@ -53,6 +55,7 @@ fun AppNotificationPreference(
override val summary = summaryFlow.collectAsStateWithLifecycle(
initialValue = stringResource(R.string.summary_placeholder)
)
+ override val enabled = stateOf(app.installed)
override val onClick = { navigateToAppNotificationSettings(context, app) }
})
}
diff --git a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
index a03fec727f4..52c8ad7b160 100644
--- a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
+++ b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
@@ -141,7 +141,9 @@ class PackageInfoPresenter(
private fun getPackageInfo() =
packageManagers.getPackageInfoAsUser(
packageName = packageName,
- flags = PackageManager.MATCH_DISABLED_COMPONENTS or PackageManager.GET_PERMISSIONS,
+ flags = PackageManager.MATCH_ANY_USER or
+ PackageManager.MATCH_DISABLED_COMPONENTS or
+ PackageManager.GET_PERMISSIONS,
userId = userId,
)
}
diff --git a/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt b/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
index 56c16df1dae..9fc358b5cf8 100644
--- a/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
+++ b/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
@@ -28,6 +28,7 @@ import androidx.compose.runtime.livedata.observeAsState
import com.android.settings.R
import com.android.settingslib.spaprivileged.model.app.AppOpsController
import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.android.settingslib.spaprivileged.model.app.installed
import com.android.settingslib.spaprivileged.model.app.userId
import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListModel
import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
@@ -67,11 +68,12 @@ class PictureInPictureListModel(private val context: Context) :
}
override fun transformItem(app: ApplicationInfo): PictureInPictureRecord {
- val packageInfo =
- packageManager.getPackageInfoAsUser(app.packageName, GET_ACTIVITIES_FLAGS, app.userId)
return createPictureInPictureRecord(
app = app,
- isSupport = packageInfo.supportsPictureInPicture(),
+ isSupport = app.installed &&
+ packageManager
+ .getPackageInfoAsUser(app.packageName, GET_ACTIVITIES_FLAGS, app.userId)
+ .supportsPictureInPicture(),
)
}
diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java
index 7303b74772a..f0a18ec5565 100644
--- a/tests/robotests/src/com/android/settings/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/UtilsTest.java
@@ -160,30 +160,6 @@ public class UtilsTest {
Utils.maybeInitializeVolume(storageManager, new Bundle());
}
- @Test
- public void getInstallationStatus_notInstalled_shouldReturnUninstalled() {
- assertThat(Utils.getInstallationStatus(new ApplicationInfo()))
- .isEqualTo(R.string.not_installed);
- }
-
- @Test
- public void getInstallationStatus_enabled_shouldReturnInstalled() {
- final ApplicationInfo info = new ApplicationInfo();
- info.flags = ApplicationInfo.FLAG_INSTALLED;
- info.enabled = true;
-
- assertThat(Utils.getInstallationStatus(info)).isEqualTo(R.string.installed);
- }
-
- @Test
- public void getInstallationStatus_disabled_shouldReturnDisabled() {
- final ApplicationInfo info = new ApplicationInfo();
- info.flags = ApplicationInfo.FLAG_INSTALLED;
- info.enabled = false;
-
- assertThat(Utils.getInstallationStatus(info)).isEqualTo(R.string.disabled);
- }
-
@Test
public void isProfileOrDeviceOwner_deviceOwnerApp_returnTrue() {
when(mDevicePolicyManager.isDeviceOwnerAppOnAnyUser(PACKAGE_NAME)).thenReturn(true);
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
index b5dfddcb5bd..2e7752e4964 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
@@ -147,6 +147,7 @@ class AllAppListTest {
val listModel = AllAppListModel(context) { stateOf(SUMMARY) }
val disabledApp = ApplicationInfo().apply {
packageName = PACKAGE_NAME
+ flags = ApplicationInfo.FLAG_INSTALLED
enabled = false
}
@@ -159,6 +160,23 @@ class AllAppListTest {
assertThat(summaryState.value).isEqualTo("$SUMMARY${System.lineSeparator()}Disabled")
}
+ @Test
+ fun allAppListModel_getSummaryWhenNotInstalled() {
+ val listModel = AllAppListModel(context) { stateOf(SUMMARY) }
+ val notInstalledApp = ApplicationInfo().apply {
+ packageName = PACKAGE_NAME
+ }
+
+ lateinit var summaryState: State
+ composeTestRule.setContent {
+ summaryState =
+ listModel.getSummary(option = 0, record = AppRecordWithSize(app = notInstalledApp))
+ }
+
+ assertThat(summaryState.value)
+ .isEqualTo("$SUMMARY${System.lineSeparator()}Not installed for this user")
+ }
+
private fun getAppListInput(): AppListInput {
lateinit var input: AppListInput
composeTestRule.setContent {
@@ -192,6 +210,7 @@ class AllAppListTest {
const val SUMMARY = "Summary"
val APP = ApplicationInfo().apply {
packageName = PACKAGE_NAME
+ flags = ApplicationInfo.FLAG_INSTALLED
}
}
}
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppNotificationPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppNotificationPreferenceTest.kt
index c54d35f3c62..37f3a119d0a 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppNotificationPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppNotificationPreferenceTest.kt
@@ -21,6 +21,7 @@ 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.assertIsNotEnabled
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
@@ -72,7 +73,7 @@ class AppNotificationPreferenceTest {
@Test
fun title_displayed() {
- setContent()
+ setContent(APP)
composeTestRule.onNodeWithText(context.getString(R.string.notifications_label))
.assertIsDisplayed()
@@ -80,14 +81,25 @@ class AppNotificationPreferenceTest {
@Test
fun summary_displayed() {
- setContent()
+ setContent(APP)
composeTestRule.onNodeWithText(SUMMARY).assertIsDisplayed()
}
+ @Test
+ fun whenNotInstalled_disable() {
+ setContent(ApplicationInfo().apply {
+ packageName = PACKAGE_NAME
+ uid = UID
+ })
+
+ composeTestRule.onNodeWithText(context.getString(R.string.notifications_label))
+ .assertIsNotEnabled()
+ }
+
@Test
fun onClick_startActivity() {
- setContent()
+ setContent(APP)
composeTestRule.onRoot().performClick()
composeTestRule.delay()
@@ -102,10 +114,10 @@ class AppNotificationPreferenceTest {
}
}
- private fun setContent() {
+ private fun setContent(app: ApplicationInfo) {
composeTestRule.setContent {
CompositionLocalProvider(LocalContext provides context) {
- AppNotificationPreference(app = APP, repository = repository)
+ AppNotificationPreference(app = app, repository = repository)
}
}
}
@@ -116,6 +128,7 @@ class AppNotificationPreferenceTest {
val APP = ApplicationInfo().apply {
packageName = PACKAGE_NAME
uid = UID
+ flags = ApplicationInfo.FLAG_INSTALLED
}
const val SUMMARY = "Summary"
}
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/PictureInPictureTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/PictureInPictureTest.kt
index 5e2b8c6e4cd..f90d63947d0 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/PictureInPictureTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/PictureInPictureTest.kt
@@ -167,6 +167,7 @@ class PictureInPictureTest {
const val PICTURE_IN_PICTURE_PACKAGE_NAME = "picture.in.picture.package.name"
val PICTURE_IN_PICTURE_APP = ApplicationInfo().apply {
packageName = PICTURE_IN_PICTURE_PACKAGE_NAME
+ flags = ApplicationInfo.FLAG_INSTALLED
}
val PICTURE_IN_PICTURE_PACKAGE_INFO = PackageInfo().apply {
packageName = PICTURE_IN_PICTURE_PACKAGE_NAME
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/RegionalFooterPreferenceControllerTest.java b/tests/unit/src/com/android/settings/regionalpreferences/RegionalFooterPreferenceControllerTest.java
new file mode 100644
index 00000000000..f0197931f04
--- /dev/null
+++ b/tests/unit/src/com/android/settings/regionalpreferences/RegionalFooterPreferenceControllerTest.java
@@ -0,0 +1,62 @@
+/**
+ * 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.regionalpreferences;
+
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.os.Looper;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settingslib.widget.FooterPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class RegionalFooterPreferenceControllerTest {
+
+ private static String KEY_FOOTER_PREFERENCE = "regional_pref_footer";
+ private Context mContext;
+ private RegionalFooterPreferenceController mRegionalFooterPreferenceController;
+
+ @Mock
+ private FooterPreference mMockFooterPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ mContext = ApplicationProvider.getApplicationContext();
+ mRegionalFooterPreferenceController = new RegionalFooterPreferenceController(mContext,
+ KEY_FOOTER_PREFERENCE);
+ }
+
+ @Test
+ public void setupFooterPreference_shouldSetAsTextInLearnMore() {
+ mRegionalFooterPreferenceController.setupFooterPreference(mMockFooterPreference);
+ verify(mMockFooterPreference).setLearnMoreText(anyString());
+ }
+}