Merge "Fix the preview couldn't be scrolled up and down when showing the scroll bar."
diff --git a/res/drawable/ic_check_24dp.xml b/res/drawable/ic_check_24dp.xml
new file mode 100644
index 0000000..5801e70
--- /dev/null
+++ b/res/drawable/ic_check_24dp.xml
@@ -0,0 +1,25 @@
+<!-- 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?androidprv:attr/colorAccentPrimaryVariant">
+ <path
+ android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"
+ android:fillColor="@android:color/white"/>
+</vector>
\ No newline at end of file
diff --git a/res/layout/accessibility_text_reading_reset_button_suw.xml b/res/layout/accessibility_text_reading_reset_button_suw.xml
deleted file mode 100644
index 97e12f3..0000000
--- a/res/layout/accessibility_text_reading_reset_button_suw.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
- -->
-
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart">
-
- <Button
- android:id="@+id/reset_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|start"
- android:paddingVertical="14dp"
- android:background="?android:attr/selectableItemBackground"
- android:textColor="?android:attr/colorAccent"
- android:textSize="16sp"
- android:text="@string/accessibility_text_reading_reset_button_title"
- android:fontFamily="@*android:string/config_bodyFontFamilyMedium" />
-</FrameLayout>
diff --git a/res/layout/dialog_sim_status.xml b/res/layout/dialog_sim_status.xml
index c169e58..4fc7f46 100644
--- a/res/layout/dialog_sim_status.xml
+++ b/res/layout/dialog_sim_status.xml
@@ -17,6 +17,7 @@
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
@@ -168,6 +169,11 @@
android:layout_height="wrap_content"
android:textIsSelectable="true"
android:text="@string/device_info_not_available"/>
+ <ImageView
+ android:id="@+id/esim_id_qrcode"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:ignore="ContentDescription" />
<TextView
style="@style/device_info_dialog_label"
diff --git a/res/layout/keyboard_layout_picker.xml b/res/layout/keyboard_layout_picker.xml
new file mode 100644
index 0000000..6b163da
--- /dev/null
+++ b/res/layout/keyboard_layout_picker.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/keyboard_layout_picker_container"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:id="@+id/keyboard_layout_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:elevation="1dp"
+ android:background="?android:attr/colorBackground"
+ android:outlineAmbientShadowColor="@android:color/transparent"
+ android:outlineSpotShadowColor="@android:color/transparent"/>
+
+ <FrameLayout
+ android:id="@+id/keyboard_layouts"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorBackground"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/preference_check_icon.xml b/res/layout/preference_check_icon.xml
new file mode 100644
index 0000000..5652ac6
--- /dev/null
+++ b/res/layout/preference_check_icon.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<ImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyboard_check_icon"
+ android:src="@drawable/ic_check_24dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginHorizontal="16dp"/>
\ No newline at end of file
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 442441d..4d9a001 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1356,8 +1356,8 @@
<item>1875000</item> <!-- 15Mbps == 1875000/s -->
</string-array>
- <!-- Array containing help message codes that should not be displayed
- during fingerprint enrollment. -->
- <integer-array name="fingerprint_acquired_ignore_list">
- </integer-array>
+ <!-- An allowlist which packages won't show summary in battery usage screen.
+ [CHAR LIMIT=NONE] -->
+ <string-array name="allowlist_hide_summary_in_battery_usage" translatable="false">
+ </string-array>
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index e7efa6f..c9b5588 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -624,4 +624,11 @@
<!-- Whether sim related information is visible to the end user. -->
<bool name="config_show_sim_info">true</bool>
+ <!-- In the case of receiving both help and progress message, display progress message. -->
+ <bool name="enrollment_progress_priority_over_help">false</bool>
+ <!-- Prioritize help message by their occurrence -->
+ <bool name="enrollment_prioritize_acquire_messages">false</bool>
+ <!-- Control messages displayed during enrollment -->
+ <bool name="enrollment_message_display_controller_flag">false</bool>
+
</resources>
diff --git a/res/values/integers.xml b/res/values/integers.xml
index d110de2..530f987 100644
--- a/res/values/integers.xml
+++ b/res/values/integers.xml
@@ -26,4 +26,11 @@
<integer name="suw_max_faces_enrollable">1</integer>
<!-- Controls the maximum number of fingerprints enrollable during SUW -->
<integer name="suw_max_fingerprints_enrollable">1</integer>
+
+ <!-- Minimum display time (in millis) for help messages in fingerprint enrollment. -->
+ <integer name="enrollment_help_minimum_time_display">0</integer>
+ <!-- Minimum display time (in millis) for progress messages in fingerprint enrollment. -->
+ <integer name="enrollment_progress_minimum_time_display">0</integer>
+ <!-- The time (in millis) to wait to collect messages in fingerprint enrollment before displaying it. -->
+ <integer name="enrollment_collect_time">0</integer>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c73f3a5..1bdac77 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1312,6 +1312,8 @@
<!-- Title of device details screen [CHAR LIMIT=28]-->
<string name="device_details_title">Device details</string>
+ <!-- Title for keyboard settings preferences. [CHAR LIMIT=50] -->
+ <string name="bluetooth_device_keyboard_settings_preference_title">Keyboard settings</string>
<!-- Title of the item to show device MAC address -->
<string name="bluetooth_device_mac_address">Device\'s Bluetooth address: <xliff:g id="address">%1$s</xliff:g></string>
<!-- Title of the items to show multuple devices MAC address [CHAR LIMIT=NONE]-->
@@ -3641,8 +3643,8 @@
<string name="available_virtual_keyboard_category">Available On-screen keyboard</string>
<!-- Title for the button to trigger the 'Manage keyboards' preference sub-screen, where the user can turn on/off installed virtual keyboards.[CHAR LIMIT=35] -->
<string name="add_virtual_keyboard">Manage on-screen keyboards</string>
- <!-- Title for the 'keyboard assistance' preference category. [CHAR LIMIT=35] -->
- <string name="keyboard_assistance_category">Keyboard assistance</string>
+ <!-- Title for the 'keyboard options' preference category. [CHAR LIMIT=35] -->
+ <string name="keyboard_options_category">Options</string>
<!-- Title for the 'physical keyboard' settings screen. [CHAR LIMIT=35] -->
<string name="physical_keyboard_title">Physical keyboard</string>
<!-- Title for the 'show virtual keyboard' preference switch. [CHAR LIMIT=35] -->
@@ -3652,7 +3654,7 @@
<!-- Title for the button to trigger the 'keyboard shortcuts helper' dialog. [CHAR LIMIT=35] -->
<string name="keyboard_shortcuts_helper">Keyboard shortcuts</string>
<!-- Summary text for the 'keyboard shortcuts helper' dialog. [CHAR LIMIT=100] -->
- <string name="keyboard_shortcuts_helper_summary">Display available shortcuts</string>
+ <string name="keyboard_shortcuts_helper_summary">Show list of shortcuts</string>
<!-- Title for the 'Work profile keyboards & tools' preference category inside Languages and inputs'. [CHAR LIMIT=50] -->
<string name="language_and_input_for_work_category_title">Work profile keyboards & tools</string>
<!-- Title for the 'Virtual keyboards for work' preference. [CHAR LIMIT=45] -->
@@ -3687,6 +3689,8 @@
<!-- Keyboard Layout Picker --> <skip />
<!-- Title for the keyboard layout picker activity. [CHAR LIMIT=35] -->
<string name="keyboard_layout_picker_title">Keyboard layouts</string>
+ <!-- Category title for the keyboard layout picker activity. [CHAR LIMIT=35] -->
+ <string name="keyboard_layout_picker_category_title">Physical keyboard layouts</string>
<!-- User dictionary settings --><skip />
<!-- User dictionary settings. The title of the list item to go into the Personal dictionary settings screen. [CHAR LIMIT=35] -->
@@ -3742,6 +3746,9 @@
<!-- Title for built-in keyboard settings -->
<string name="builtin_keyboard_settings_title">Physical keyboard</string>
+ <!-- Title for enabled locales keyboard layout page -->
+ <string name="enabled_locales_keyboard_layout">Layout</string>
+
<!-- Title for the screen that lets the user choose a gadget to add to the home screen
(or other screens that can host gadgets). Note to translators: we're still determining
the final name for Gadgets/Widgets, so please translate both for now. -->
@@ -6536,7 +6543,11 @@
<string name="keywords_face_unlock">face, unlock, auth, sign in</string>
<string name="keywords_biometric_unlock">face, unlock, auth, sign in, fingerprint, biometric</string>
<string name="keywords_imei_info">imei, meid, min, prl version, imei sv</string>
- <string name="keywords_sim_status">network, mobile network state, service state, signal strength, mobile network type, roaming, iccid, eid</string>
+ <string name="keywords_sim_status">network, mobile network state, service state, signal strength, mobile network type, roaming</string>
+ <string name="keywords_sim_status_esim">network, mobile network state, service state, signal strength, mobile network type, roaming, eid</string>
+ <string name="keywords_sim_status_iccid">network, mobile network state, service state, signal strength, mobile network type, roaming, iccid</string>
+ <string name="keywords_sim_status_iccid_esim">network, mobile network state, service state, signal strength, mobile network type, roaming, iccid, eid</string>
+ <string name="keywords_esim_eid">eid</string>
<string name="keywords_model_and_hardware">serial number, hardware version</string>
<string name="keywords_android_version">android security patch level, baseband version, kernel version</string>
<!-- Search keywords for dark mode settings [CHAR LIMIT=NONE] -->
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index 5cd7c3a..c031960 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -88,6 +88,12 @@
settings:controller="com.android.settings.accessibility.LiveCaptionPreferenceController"/>
</PreferenceCategory>
+ <Preference
+ android:key="keyboard_settings"
+ android:persistent="false"
+ android:title="@string/bluetooth_device_keyboard_settings_preference_title"
+ settings:controller="com.android.settings.inputmethod.KeyboardSettingsPreferenceController"/>
+
<com.android.settingslib.widget.FooterPreference
android:key="device_details_footer"
android:selectable="false"
diff --git a/res/xml/keyboard_settings.xml b/res/xml/keyboard_settings.xml
index bff1160..9a3ac1a 100644
--- a/res/xml/keyboard_settings.xml
+++ b/res/xml/keyboard_settings.xml
@@ -20,8 +20,7 @@
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/keyboard_settings">
<PreferenceCategory
- android:key="keyboards_category"
- android:title="@string/keyboard_and_input_methods_category">
+ android:key="keyboards_category">
<Preference
android:key="virtual_keyboard_pref"
android:title="@string/virtual_keyboard_category"
diff --git a/res/xml/keyboard_settings_enabled_locales_list.xml b/res/xml/keyboard_settings_enabled_locales_list.xml
new file mode 100644
index 0000000..06b8d5f
--- /dev/null
+++ b/res/xml/keyboard_settings_enabled_locales_list.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<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>
\ No newline at end of file
diff --git a/res/xml/new_keyboard_layout_picker_fragment.xml b/res/xml/new_keyboard_layout_picker_fragment.xml
new file mode 100644
index 0000000..0a76984
--- /dev/null
+++ b/res/xml/new_keyboard_layout_picker_fragment.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="keyboard_layout_picker_list"
+ settings:controller="com.android.settings.inputmethod.NewKeyboardLayoutPickerController">
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/new_keyboard_layout_picker_title.xml b/res/xml/new_keyboard_layout_picker_title.xml
new file mode 100644
index 0000000..cd03b91
--- /dev/null
+++ b/res/xml/new_keyboard_layout_picker_title.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:key="keyboard_layout_picker_title">
+ <!-- Separate title from new_keyboard_layout_picker_fragment to avoid being moved to the top -->
+ <PreferenceCategory
+ android:key="keyboard_layout_picker_title"
+ android:title="@string/keyboard_layout_picker_category_title">
+ </PreferenceCategory>
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/physical_keyboard_settings.xml b/res/xml/physical_keyboard_settings.xml
index 96946a9..54a5c65 100644
--- a/res/xml/physical_keyboard_settings.xml
+++ b/res/xml/physical_keyboard_settings.xml
@@ -19,8 +19,8 @@
<!-- Additional preference screens are inserted here programmatically
with low order values to set the key map of each attached keyboard. -->
<PreferenceCategory
- android:key="keyboard_assistance_category"
- android:title="@string/keyboard_assistance_category">
+ android:key="keyboard_options_category"
+ android:title="@string/keyboard_options_category">
<SwitchPreference
android:key="show_virtual_keyboard_switch"
android:title="@string/show_ime"
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 23f8fd3..7b1500b 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -43,6 +43,7 @@
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.RestrictedPreference;
+import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.search.SearchIndexableRaw;
@@ -303,6 +304,7 @@
void updateAllPreferences() {
updateSystemPreferences();
updateServicePreferences();
+ updatePreferencesState();
}
private void registerContentMonitors() {
@@ -478,6 +480,13 @@
// Do nothing.
}
+ private void updatePreferencesState() {
+ final List<AbstractPreferenceController> controllers = new ArrayList<>();
+ getPreferenceControllers().forEach(controllers::addAll);
+ controllers.forEach(controller -> controller.updateState(
+ findPreference(controller.getPreferenceKey())));
+ }
+
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.accessibility_settings) {
@Override
diff --git a/src/com/android/settings/accessibility/ColorAndMotionFragment.java b/src/com/android/settings/accessibility/ColorAndMotionFragment.java
index 7f55053..921aa4e 100644
--- a/src/com/android/settings/accessibility/ColorAndMotionFragment.java
+++ b/src/com/android/settings/accessibility/ColorAndMotionFragment.java
@@ -19,6 +19,7 @@
import android.app.settings.SettingsEnums;
import android.hardware.display.ColorDisplayManager;
import android.os.Bundle;
+import android.os.Handler;
import android.provider.Settings;
import androidx.preference.Preference;
@@ -28,8 +29,12 @@
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable;
+import java.util.ArrayList;
+import java.util.List;
+
/** Accessibility settings for color and motion. */
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class ColorAndMotionFragment extends DashboardFragment {
@@ -46,18 +51,48 @@
private Preference mDisplayDaltonizerPreferenceScreen;
private SwitchPreference mToggleDisableAnimationsPreference;
private SwitchPreference mToggleLargePointerIconPreference;
+ private AccessibilitySettingsContentObserver mSettingsContentObserver;
+
+ private final List<String> mShortcutFeatureKeys = new ArrayList<>();
@Override
public int getMetricsCategory() {
return SettingsEnums.ACCESSIBILITY_COLOR_AND_MOTION;
}
-
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
initializeAllPreferences();
updateSystemPreferences();
+
+ mShortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+ mShortcutFeatureKeys.add(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
+
+ mSettingsContentObserver = new AccessibilitySettingsContentObserver(new Handler());
+ mSettingsContentObserver.registerKeysToObserverCallback(mShortcutFeatureKeys,
+ key -> updatePreferencesState());
+ }
+
+ private void updatePreferencesState() {
+ final List<AbstractPreferenceController> controllers = new ArrayList<>();
+ getPreferenceControllers().forEach(controllers::addAll);
+ controllers.forEach(controller -> controller.updateState(
+ findPreference(controller.getPreferenceKey())));
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ mSettingsContentObserver.register(getContentResolver());
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+
+ mSettingsContentObserver.unregister(getContentResolver());
}
@Override
diff --git a/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java b/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java
index 2078112..51a775e 100644
--- a/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java
+++ b/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java
@@ -25,6 +25,8 @@
import com.android.settings.core.BasePreferenceController;
import com.android.settings.widget.LabeledSeekBarPreference;
+import java.util.Optional;
+
/**
* The controller of {@link LabeledSeekBarPreference} that listens to display size and font size
* settings changes and updates preview size threshold smoothly.
@@ -33,19 +35,24 @@
TextReadingResetController.ResetStateListener {
private final PreviewSizeData<? extends Number> mSizeData;
private boolean mSeekByTouch;
- private ProgressInteractionListener mInteractionListener;
+ private Optional<ProgressInteractionListener> mInteractionListener = Optional.empty();
private LabeledSeekBarPreference mSeekBarPreference;
private final SeekBar.OnSeekBarChangeListener mSeekBarChangeListener =
new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- mInteractionListener.notifyPreferenceChanged();
-
- if (!mSeekByTouch && mInteractionListener != null) {
- mInteractionListener.onProgressChanged();
+ if (mInteractionListener.isEmpty()) {
+ return;
}
+ final ProgressInteractionListener interactionListener =
+ mInteractionListener.get();
+ interactionListener.notifyPreferenceChanged();
+
+ if (!mSeekByTouch) {
+ interactionListener.onProgressChanged();
+ }
}
@Override
@@ -57,9 +64,7 @@
public void onStopTrackingTouch(SeekBar seekBar) {
mSeekByTouch = false;
- if (mInteractionListener != null) {
- mInteractionListener.onEndTrackingTouch();
- }
+ mInteractionListener.ifPresent(ProgressInteractionListener::onEndTrackingTouch);
}
};
@@ -70,7 +75,7 @@
}
void setInteractionListener(ProgressInteractionListener interactionListener) {
- mInteractionListener = interactionListener;
+ mInteractionListener = Optional.ofNullable(interactionListener);
}
@Override
@@ -95,6 +100,10 @@
public void resetState() {
final int defaultProgress = mSizeData.getValues().indexOf(mSizeData.getDefaultValue());
mSeekBarPreference.setProgress(defaultProgress);
+
+ // Immediately take the effect of updating the progress to avoid waiting for receiving
+ // the event to delay update.
+ mInteractionListener.ifPresent(ProgressInteractionListener::onProgressChanged);
}
diff --git a/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java b/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java
index d1614ca..22bef28 100644
--- a/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java
@@ -18,11 +18,11 @@
import static com.android.settings.accessibility.TextReadingResetController.ResetStateListener;
+import android.app.Activity;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
@@ -44,7 +44,6 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -55,8 +54,7 @@
public class TextReadingPreferenceFragment extends DashboardFragment {
public static final String EXTRA_LAUNCHED_FROM = "launched_from";
private static final String TAG = "TextReadingPreferenceFragment";
- private static final String CATEGORY_FOR_ANYTHING_ELSE =
- "com.android.settings.suggested.category.DISPLAY_SETTINGS";
+ private static final String SETUP_WIZARD_PACKAGE = "setupwizard";
static final String FONT_SIZE_KEY = "font_size";
static final String DISPLAY_SIZE_KEY = "display_size";
static final String BOLD_TEXT_KEY = "toggle_force_bold_text";
@@ -179,10 +177,8 @@
new TextReadingResetController(context, RESET_KEY,
v -> showDialog(DialogEnums.DIALOG_RESET_SETTINGS));
resetController.setEntryPoint(mEntryPoint);
+ resetController.setVisible(!WizardManagerHelper.isAnySetupWizard(getIntent()));
controllers.add(resetController);
- if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
- resetController.setSetupWizardStyle();
- }
return controllers;
}
@@ -230,6 +226,13 @@
}
}
+ protected boolean isCallingFromAnythingElseEntryPoint() {
+ final Activity activity = getActivity();
+ final String callingPackage = activity != null ? activity.getCallingPackage() : null;
+
+ return callingPackage != null && callingPackage.contains(SETUP_WIZARD_PACKAGE);
+ }
+
@VisibleForTesting
DisplaySizeData createDisplaySizeData(Context context) {
return new DisplaySizeData(context);
@@ -242,14 +245,7 @@
return;
}
- final Intent intent = getIntent();
- if (intent == null) {
- mEntryPoint = EntryPoint.UNKNOWN_ENTRY;
- return;
- }
-
- final Set<String> categories = intent.getCategories();
- mEntryPoint = categories != null && categories.contains(CATEGORY_FOR_ANYTHING_ELSE)
+ mEntryPoint = isCallingFromAnythingElseEntryPoint()
? EntryPoint.SUW_ANYTHING_ELSE : EntryPoint.UNKNOWN_ENTRY;
}
diff --git a/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java b/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java
index b025cf5..cdbfe5f 100644
--- a/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java
+++ b/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizard.java
@@ -16,6 +16,10 @@
package com.android.settings.accessibility;
+import static android.app.Activity.RESULT_CANCELED;
+
+import static com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums.DIALOG_RESET_SETTINGS;
+
import android.app.settings.SettingsEnums;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -28,9 +32,10 @@
import com.android.settings.R;
import com.android.settingslib.Utils;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupdesign.GlifPreferenceLayout;
-
/**
* A {@link androidx.preference.PreferenceFragmentCompat} that displays the settings page related
* to the text and reading option in the SetupWizard.
@@ -48,6 +53,28 @@
icon.setTintList(Utils.getColorAttr(getContext(), android.R.attr.colorPrimary));
AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
/* description= */ null, icon);
+
+ final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
+ mixin.setSecondaryButton(
+ new FooterButton.Builder(getContext())
+ .setText(R.string.accessibility_text_reading_reset_button_title)
+ .setListener(l -> showDialog(DIALOG_RESET_SETTINGS))
+ .setButtonType(FooterButton.ButtonType.CLEAR)
+ .setTheme(R.style.SudGlifButton_Secondary)
+ .build());
+
+ if (isCallingFromAnythingElseEntryPoint()) {
+ mixin.setPrimaryButton(
+ new FooterButton.Builder(getContext())
+ .setText(R.string.done)
+ .setListener(l -> {
+ setResult(RESULT_CANCELED);
+ finish();
+ })
+ .setButtonType(FooterButton.ButtonType.DONE)
+ .setTheme(R.style.SudGlifButton_Primary)
+ .build());
+ }
}
@Override
diff --git a/src/com/android/settings/accessibility/TextReadingResetController.java b/src/com/android/settings/accessibility/TextReadingResetController.java
index 206090c..325052c 100644
--- a/src/com/android/settings/accessibility/TextReadingResetController.java
+++ b/src/com/android/settings/accessibility/TextReadingResetController.java
@@ -23,7 +23,6 @@
import androidx.preference.PreferenceScreen;
import com.android.settings.accessibility.TextReadingPreferenceFragment.EntryPoint;
-import com.android.settings.accessibility.TextReadingResetPreference.ButtonStyle;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.instrumentation.SettingsStatsLog;
@@ -31,8 +30,7 @@
* The controller of the reset button in the text and reading options page.
*/
class TextReadingResetController extends BasePreferenceController {
- @ButtonStyle
- private int mButtonStyle;
+ private boolean mIsVisible;
private final View.OnClickListener mOnResetClickListener;
@EntryPoint
@@ -67,11 +65,11 @@
}
});
- resetPreference.setSetupWizardStyle(mButtonStyle);
+ setVisible(screen, getPreferenceKey(), mIsVisible);
}
- void setSetupWizardStyle() {
- mButtonStyle = ButtonStyle.SUW;
+ void setVisible(boolean isVisible) {
+ mIsVisible = isVisible;
}
/**
diff --git a/src/com/android/settings/accessibility/TextReadingResetPreference.java b/src/com/android/settings/accessibility/TextReadingResetPreference.java
index 64f3834..9518de2 100644
--- a/src/com/android/settings/accessibility/TextReadingResetPreference.java
+++ b/src/com/android/settings/accessibility/TextReadingResetPreference.java
@@ -20,15 +20,11 @@
import android.util.AttributeSet;
import android.view.View;
-import androidx.annotation.IntDef;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
/**
* The preference which is used for resetting the status of all preferences in the display size
* and text page.
@@ -36,20 +32,10 @@
public class TextReadingResetPreference extends Preference {
private View.OnClickListener mOnResetClickListener;
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- ButtonStyle.DEFAULT,
- ButtonStyle.SUW,
- })
- @interface ButtonStyle {
- int DEFAULT = 0;
- int SUW = 1;
- }
-
public TextReadingResetPreference(Context context, AttributeSet attrs) {
super(context, attrs);
- setSetupWizardStyle(ButtonStyle.DEFAULT);
+ setLayoutResource(R.layout.accessibility_text_reading_reset_button);
}
@Override
@@ -60,13 +46,6 @@
view.setOnClickListener(mOnResetClickListener);
}
- void setSetupWizardStyle(@ButtonStyle int style) {
- final int layoutResId = (style == ButtonStyle.SUW)
- ? R.layout.accessibility_text_reading_reset_button_suw
- : R.layout.accessibility_text_reading_reset_button;
- setLayoutResource(layoutResId);
- }
-
void setOnResetClickListener(View.OnClickListener resetClickListener) {
mOnResetClickListener = resetClickListener;
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index 3ab2f92..5b8cd68 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -352,8 +352,8 @@
@Override
protected BiometricEnrollSidecar getSidecar() {
- final FingerprintEnrollSidecar sidecar = new FingerprintEnrollSidecar();
- sidecar.setEnrollReason(FingerprintManager.ENROLL_ENROLL);
+ final FingerprintEnrollSidecar sidecar = new FingerprintEnrollSidecar(this,
+ FingerprintManager.ENROLL_ENROLL);
return sidecar;
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
index 200b8c5..778ee5c 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
@@ -293,8 +293,8 @@
mSidecar = (FingerprintEnrollSidecar) getSupportFragmentManager().findFragmentByTag(
FingerprintEnrollEnrolling.TAG_SIDECAR);
if (mSidecar == null) {
- mSidecar = new FingerprintEnrollSidecar();
- mSidecar.setEnrollReason(FingerprintManager.ENROLL_FIND_SENSOR);
+ mSidecar = new FingerprintEnrollSidecar(this,
+ FingerprintManager.ENROLL_FIND_SENSOR);
getSupportFragmentManager().beginTransaction()
.add(mSidecar, FingerprintEnrollEnrolling.TAG_SIDECAR)
.commitAllowingStateLoss();
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java
index d1e512e..b3b9975 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java
@@ -16,19 +16,19 @@
package com.android.settings.biometrics.fingerprint;
+import static android.hardware.fingerprint.FingerprintManager.ENROLL_ENROLL;
+
import android.app.Activity;
import android.app.settings.SettingsEnums;
+import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
+import android.os.SystemClock;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.biometrics.BiometricEnrollSidecar;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
/**
* Sidecar fragment to handle the state around fingerprint enrollment.
*/
@@ -37,19 +37,41 @@
private FingerprintUpdater mFingerprintUpdater;
private @FingerprintManager.EnrollReason int mEnrollReason;
- private Set<Integer> mHelpIgnore;
+ private final MessageDisplayController mMessageDisplayController;
+ private final boolean mMessageDisplayControllerFlag;
+
+ /**
+ * Create a new FingerprintEnrollSidecar object.
+ * @param context associated context
+ * @param enrollReason reason for enrollment
+ */
+ public FingerprintEnrollSidecar(Context context,
+ @FingerprintManager.EnrollReason int enrollReason) {
+ mEnrollReason = enrollReason;
+
+ int helpMinimumDisplayTime = context.getResources().getInteger(
+ R.integer.enrollment_help_minimum_time_display);
+ int progressMinimumDisplayTime = context.getResources().getInteger(
+ R.integer.enrollment_progress_minimum_time_display);
+ boolean progressPriorityOverHelp = context.getResources().getBoolean(
+ R.bool.enrollment_progress_priority_over_help);
+ boolean prioritizeAcquireMessages = context.getResources().getBoolean(
+ R.bool.enrollment_prioritize_acquire_messages);
+ int collectTime = context.getResources().getInteger(
+ R.integer.enrollment_collect_time);
+ mMessageDisplayControllerFlag = context.getResources().getBoolean(
+ R.bool.enrollment_message_display_controller_flag);
+
+ mMessageDisplayController = new MessageDisplayController(context.getMainThreadHandler(),
+ mEnrollmentCallback, SystemClock.elapsedRealtimeClock(), helpMinimumDisplayTime,
+ progressMinimumDisplayTime, progressPriorityOverHelp, prioritizeAcquireMessages,
+ collectTime);
+ }
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mFingerprintUpdater = new FingerprintUpdater(activity);
- final int[] ignoreAcquiredInfo = getResources().getIntArray(
- R.array.fingerprint_acquired_ignore_list);
- mHelpIgnore = new HashSet<>();
- for (int acquiredInfo: ignoreAcquiredInfo) {
- mHelpIgnore.add(acquiredInfo);
- }
- mHelpIgnore = Collections.unmodifiableSet(mHelpIgnore);
}
@Override
@@ -62,8 +84,16 @@
getString(R.string.fingerprint_intro_error_unknown));
return;
}
- mFingerprintUpdater.enroll(mToken, mEnrollmentCancel, mUserId, mEnrollmentCallback,
- mEnrollReason);
+
+ if (mEnrollReason == ENROLL_ENROLL && mMessageDisplayControllerFlag) {
+ //API calls need to be processed for {@link FingerprintEnrollEnrolling}
+ mFingerprintUpdater.enroll(mToken, mEnrollmentCancel, mUserId,
+ mMessageDisplayController, mEnrollReason);
+ } else {
+ //No processing required for {@link FingerprintEnrollFindSensor}
+ mFingerprintUpdater.enroll(mToken, mEnrollmentCancel, mUserId, mEnrollmentCallback,
+ mEnrollReason);
+ }
}
public void setEnrollReason(@FingerprintManager.EnrollReason int enrollReason) {
@@ -80,9 +110,6 @@
@Override
public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
- if (mHelpIgnore.contains(helpMsgId)) {
- return;
- }
FingerprintEnrollSidecar.super.onEnrollmentHelp(helpMsgId, helpString);
}
diff --git a/src/com/android/settings/biometrics/fingerprint/MessageDisplayController.java b/src/com/android/settings/biometrics/fingerprint/MessageDisplayController.java
new file mode 100644
index 0000000..11f3ee3
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint/MessageDisplayController.java
@@ -0,0 +1,264 @@
+/*
+ * 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.fingerprint;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Handler;
+
+import java.time.Clock;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+
+/**
+ * Processes message provided from the enrollment callback and filters them based
+ * on the below configurable flags. This is primarily used to reduce the rate
+ * at which messages come through, which in turns eliminates UI flicker.
+ */
+public class MessageDisplayController extends FingerprintManager.EnrollmentCallback {
+
+ private final int mHelpMinimumDisplayTime;
+ private final int mProgressMinimumDisplayTime;
+ private final boolean mProgressPriorityOverHelp;
+ private final boolean mPrioritizeAcquireMessages;
+ private final int mCollectTime;
+ @NonNull
+ private final Deque<HelpMessage> mHelpMessageList;
+ @NonNull
+ private final Deque<ProgressMessage> mProgressMessageList;
+ @NonNull
+ private final Handler mHandler;
+ @NonNull
+ private final Clock mClock;
+ @NonNull
+ private final Runnable mDisplayMessageRunnable;
+
+ @Nullable
+ private ProgressMessage mLastProgressMessageDisplayed;
+ private boolean mMustDisplayProgress;
+ private boolean mWaitingForMessage;
+ @NonNull FingerprintManager.EnrollmentCallback mEnrollmentCallback;
+
+ private abstract static class Message {
+ long mTimeStamp = 0;
+ abstract void display();
+ }
+
+ private class HelpMessage extends Message {
+ private final int mHelpMsgId;
+ private final CharSequence mHelpString;
+
+ HelpMessage(int helpMsgId, CharSequence helpString) {
+ mHelpMsgId = helpMsgId;
+ mHelpString = helpString;
+ mTimeStamp = mClock.millis();
+ }
+
+ @Override
+ void display() {
+ mEnrollmentCallback.onEnrollmentHelp(mHelpMsgId, mHelpString);
+ mHandler.postDelayed(mDisplayMessageRunnable, mHelpMinimumDisplayTime);
+ }
+ }
+
+ private class ProgressMessage extends Message {
+ private final int mRemaining;
+
+ ProgressMessage(int remaining) {
+ mRemaining = remaining;
+ mTimeStamp = mClock.millis();
+ }
+
+ @Override
+ void display() {
+ mEnrollmentCallback.onEnrollmentProgress(mRemaining);
+ mLastProgressMessageDisplayed = this;
+ mHandler.postDelayed(mDisplayMessageRunnable, mProgressMinimumDisplayTime);
+ }
+ }
+
+ /**
+ * Creating a MessageDisplayController object.
+ * @param handler main handler to run message queue
+ * @param enrollmentCallback callback to display messages
+ * @param clock real time system clock
+ * @param helpMinimumDisplayTime the minimum duration (in millis) that
+* a help message needs to be displayed for
+ * @param progressMinimumDisplayTime the minimum duration (in millis) that
+* a progress message needs to be displayed for
+ * @param progressPriorityOverHelp if true, then progress message is displayed
+* when both help and progress message APIs have been called
+ * @param prioritizeAcquireMessages if true, then displays the help message
+* which has occurred the most after the last display message
+ * @param collectTime the waiting time (in millis) to collect messages when it is idle
+ */
+ public MessageDisplayController(@NonNull Handler handler,
+ FingerprintManager.EnrollmentCallback enrollmentCallback,
+ @NonNull Clock clock, int helpMinimumDisplayTime, int progressMinimumDisplayTime,
+ boolean progressPriorityOverHelp, boolean prioritizeAcquireMessages,
+ int collectTime) {
+ mClock = clock;
+ mWaitingForMessage = false;
+ mHelpMessageList = new ArrayDeque<>();
+ mProgressMessageList = new ArrayDeque<>();
+ mHandler = handler;
+ mEnrollmentCallback = enrollmentCallback;
+
+ mHelpMinimumDisplayTime = helpMinimumDisplayTime;
+ mProgressMinimumDisplayTime = progressMinimumDisplayTime;
+ mProgressPriorityOverHelp = progressPriorityOverHelp;
+ mPrioritizeAcquireMessages = prioritizeAcquireMessages;
+ mCollectTime = collectTime;
+
+ mDisplayMessageRunnable = () -> {
+ long timeStamp = mClock.millis();
+ Message messageToDisplay = getMessageToDisplay(timeStamp);
+
+ if (messageToDisplay != null) {
+ messageToDisplay.display();
+ } else {
+ mWaitingForMessage = true;
+ }
+ };
+
+ mHandler.postDelayed(mDisplayMessageRunnable, 0);
+ }
+
+ /**
+ * Adds help message to the queue to be processed later.
+ *
+ * @param helpMsgId message Id associated with the help message
+ * @param helpString string associated with the help message
+ */
+ @Override
+ public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
+ mHelpMessageList.add(new HelpMessage(helpMsgId, helpString));
+
+ if (mWaitingForMessage) {
+ mWaitingForMessage = false;
+ mHandler.postDelayed(mDisplayMessageRunnable, mCollectTime);
+ }
+ }
+
+ /**
+ * Adds progress change message to the queue to be processed later.
+ *
+ * @param remaining remaining number of steps to complete enrollment
+ */
+ @Override
+ public void onEnrollmentProgress(int remaining) {
+ mProgressMessageList.add(new ProgressMessage(remaining));
+
+ if (mWaitingForMessage) {
+ mWaitingForMessage = false;
+ mHandler.postDelayed(mDisplayMessageRunnable, mCollectTime);
+ }
+ }
+
+ @Override
+ public void onEnrollmentError(int errMsgId, CharSequence errString) {
+ mEnrollmentCallback.onEnrollmentError(errMsgId, errString);
+ }
+
+ private Message getMessageToDisplay(long timeStamp) {
+ ProgressMessage progressMessageToDisplay = getProgressMessageToDisplay(timeStamp);
+ if (mMustDisplayProgress) {
+ mMustDisplayProgress = false;
+ if (progressMessageToDisplay != null) {
+ return progressMessageToDisplay;
+ }
+ if (mLastProgressMessageDisplayed != null) {
+ return mLastProgressMessageDisplayed;
+ }
+ }
+
+ Message helpMessageToDisplay = getHelpMessageToDisplay(timeStamp);
+ if (helpMessageToDisplay != null || progressMessageToDisplay != null) {
+ if (mProgressPriorityOverHelp && progressMessageToDisplay != null) {
+ return progressMessageToDisplay;
+ } else if (helpMessageToDisplay != null) {
+ if (progressMessageToDisplay != null) {
+ mMustDisplayProgress = true;
+ mLastProgressMessageDisplayed = progressMessageToDisplay;
+ }
+ return helpMessageToDisplay;
+ } else {
+ return progressMessageToDisplay;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ private ProgressMessage getProgressMessageToDisplay(long timeStamp) {
+ ProgressMessage finalProgressMessage = null;
+ while (mProgressMessageList != null && !mProgressMessageList.isEmpty()) {
+ Message message = mProgressMessageList.peekFirst();
+ if (message.mTimeStamp <= timeStamp) {
+ ProgressMessage progressMessage = mProgressMessageList.pollFirst();
+ if (mLastProgressMessageDisplayed != null
+ && mLastProgressMessageDisplayed.mRemaining == progressMessage.mRemaining) {
+ continue;
+ }
+ finalProgressMessage = progressMessage;
+ } else {
+ break;
+ }
+ }
+
+ return finalProgressMessage;
+ }
+
+ private HelpMessage getHelpMessageToDisplay(long timeStamp) {
+ HashMap<CharSequence, Integer> messageCount = new HashMap<>();
+ HelpMessage finalHelpMessage = null;
+
+ while (mHelpMessageList != null && !mHelpMessageList.isEmpty()) {
+ Message message = mHelpMessageList.peekFirst();
+ if (message.mTimeStamp <= timeStamp) {
+ finalHelpMessage = mHelpMessageList.pollFirst();
+ CharSequence errString = finalHelpMessage.mHelpString;
+ messageCount.put(errString, messageCount.getOrDefault(errString, 0) + 1);
+ } else {
+ break;
+ }
+ }
+ if (mPrioritizeAcquireMessages) {
+ finalHelpMessage = prioritizeHelpMessageByCount(messageCount);
+ }
+
+ return finalHelpMessage;
+ }
+
+ private HelpMessage prioritizeHelpMessageByCount(HashMap<CharSequence, Integer> messageCount) {
+ int maxCount = 0;
+ CharSequence maxCountMessage = null;
+
+ for (CharSequence key :
+ messageCount.keySet()) {
+ if (maxCount < messageCount.get(key)) {
+ maxCountMessage = key;
+ maxCount = messageCount.get(key);
+ }
+ }
+
+ return maxCountMessage != null ? new HelpMessage(0 /* errMsgId */,
+ maxCountMessage) : null;
+ }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 406ac69..f68cc40 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -47,6 +47,7 @@
import com.android.settings.connecteddevice.stylus.StylusDevicesController;
import com.android.settings.core.SettingsUIDeviceConfig;
import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settings.inputmethod.KeyboardSettingsPreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.slices.BlockingSlicePrefController;
import com.android.settings.slices.SlicePreferenceController;
@@ -171,6 +172,7 @@
}
use(AdvancedBluetoothDetailsHeaderController.class).init(mCachedDevice);
use(LeAudioBluetoothDetailsHeaderController.class).init(mCachedDevice, mManager);
+ use(KeyboardSettingsPreferenceController.class).init(mCachedDevice, getActivity());
final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(
context).getBluetoothFeatureProvider();
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 7904fdb..da81f6e 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -120,6 +120,7 @@
import com.android.settings.inputmethod.AvailableVirtualKeyboardFragment;
import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
import com.android.settings.inputmethod.KeyboardSettings;
+import com.android.settings.inputmethod.NewKeyboardLayoutEnabledLocalesFragment;
import com.android.settings.inputmethod.PhysicalKeyboardFragment;
import com.android.settings.inputmethod.SpellCheckersSettings;
import com.android.settings.inputmethod.UserDictionaryList;
@@ -214,6 +215,7 @@
LanguageAndInputSettings.class.getName(),
LanguageSettings.class.getName(),
KeyboardSettings.class.getName(),
+ NewKeyboardLayoutEnabledLocalesFragment.class.getName(),
SpellCheckersSettings.class.getName(),
UserDictionaryList.class.getName(),
UserDictionarySettings.class.getName(),
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
index c093472..855cd12 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
@@ -22,6 +22,7 @@
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
@@ -72,7 +73,8 @@
/**
* Controller for Sim Status information within the About Phone Settings page.
*/
-public class SimStatusDialogController implements LifecycleObserver {
+public class SimStatusDialogController implements LifecycleObserver,
+ DialogInterface.OnShowListener {
private final static String TAG = "SimStatusDialogCtrl";
@@ -107,6 +109,8 @@
@VisibleForTesting
final static int EID_INFO_VALUE_ID = R.id.esim_id_value;
@VisibleForTesting
+ final static int EID_INFO_QRCODE_ID = R.id.esim_id_qrcode;
+ @VisibleForTesting
final static int IMS_REGISTRATION_STATE_LABEL_ID = R.id.ims_reg_state_label;
@VisibleForTesting
final static int IMS_REGISTRATION_STATE_VALUE_ID = R.id.ims_reg_state_value;
@@ -158,6 +162,7 @@
private boolean mShowLatestAreaInfo;
private boolean mIsRegisteredListener = false;
+ private AtomicReference<String> mEid = null;
private final BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() {
@Override
@@ -264,6 +269,19 @@
}
/**
+ * Callback when dialog end of show().
+ */
+ public void onShow(DialogInterface dialog) {
+ if (mEid != null) {
+ String eidText = mEid.get();
+ if (eidText != null) {
+ // Present QR code after the completion of layout
+ mDialog.setQrCode(EID_INFO_QRCODE_ID, eidText);
+ }
+ }
+ }
+
+ /**
* Deinitialization works
*/
public void deinitialize() {
@@ -618,8 +636,8 @@
@VisibleForTesting
protected void requestForUpdateEid() {
ThreadUtils.postOnBackgroundThread(() -> {
- final AtomicReference<String> eid = getEid(mSlotIndex);
- ThreadUtils.postOnMainThread(() -> updateEid(eid));
+ mEid = getEid(mSlotIndex);
+ ThreadUtils.postOnMainThread(() -> updateEid(mEid));
});
}
@@ -663,11 +681,20 @@
@VisibleForTesting
protected void updateEid(AtomicReference<String> eid) {
+ boolean removeQrCode = true;
if (eid == null) {
mDialog.removeSettingFromScreen(EID_INFO_LABEL_ID);
mDialog.removeSettingFromScreen(EID_INFO_VALUE_ID);
- } else if (eid.get() != null) {
- mDialog.setText(EID_INFO_VALUE_ID, eid.get());
+ mDialog.removeSettingFromScreen(EID_INFO_QRCODE_ID);
+ } else {
+ String eidText = eid.get();
+ if (eidText != null) {
+ mDialog.setText(EID_INFO_VALUE_ID, eidText);
+ removeQrCode = (eidText == "");
+ }
+ }
+ if (removeQrCode) {
+ mDialog.removeSettingFromScreen(EID_INFO_QRCODE_ID);
}
}
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java
index 96acd43..3bd9b34 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java
@@ -19,11 +19,14 @@
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.os.Bundle;
+import android.graphics.Bitmap;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
+import android.widget.ImageView;
import android.widget.TextView;
+import android.util.Log;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
@@ -32,6 +35,7 @@
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.deviceinfo.PhoneNumberUtil;
+import com.android.settingslib.qrcode.QrCodeGenerator;
import java.util.Arrays;
import java.util.stream.IntStream;
@@ -80,6 +84,7 @@
Dialog dlg = builder.setView(mRootView).create();
dlg.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE);
+ dlg.setOnShowListener(mController);
return dlg;
}
@@ -107,6 +112,10 @@
.sorted().toArray();
public void setText(int viewId, CharSequence text) {
+ setText(viewId, text, true);
+ }
+
+ public void setText(int viewId, CharSequence text, boolean enableCopy) {
final TextView textView = mRootView.findViewById(viewId);
if (textView == null) {
return;
@@ -117,5 +126,21 @@
text = PhoneNumberUtil.expandByTts(text);
}
textView.setText(text);
+ textView.setTextIsSelectable(enableCopy);
+ }
+
+ public void setQrCode(int viewId, String qrcodeText) {
+ ImageView qrCodeView = (ImageView) mRootView.findViewById(viewId);
+
+ Bitmap qrCodeBitmap = null;
+ try {
+ qrCodeBitmap = QrCodeGenerator.encodeQrCode(qrcodeText, qrCodeView.getWidth());
+ } catch (Exception exception) {
+ Log.w(TAG, "Error when presenting QR code in + " + qrCodeView, exception);
+ }
+ if (qrCodeBitmap == null) {
+ return;
+ }
+ qrCodeView.setImageBitmap(qrCodeBitmap);
}
}
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceController.java
index b75853d..16f04df 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceController.java
@@ -31,6 +31,7 @@
import com.android.settings.core.BasePreferenceController;
import com.android.settings.network.SubscriptionUtil;
import com.android.settingslib.Utils;
+import com.android.settingslib.search.SearchIndexableRaw;
import java.util.ArrayList;
import java.util.List;
@@ -159,4 +160,28 @@
Preference createNewPreference(Context context) {
return new Preference(context);
}
+
+ @Override
+ public void updateDynamicRawDataToIndex(List<SearchIndexableRaw> rawData) {
+ int simSlot = getSimSlotIndex();
+ SubscriptionInfo subInfo = getSubscriptionInfo(simSlot);
+ if (subInfo == null) {
+ /**
+ * Only add to search when SIM is active
+ * (presented in SIM Slot Status as availavle.)
+ */
+ return;
+ }
+
+ /* Have different search keywork when comes to eSIM */
+ int keywordId = subInfo.isEmbedded() ?
+ R.string.keywords_sim_status_esim : R.string.keywords_sim_status;
+
+ SearchIndexableRaw data = new SearchIndexableRaw(mContext);
+ data.key = getPreferenceKey();
+ data.title = getPreferenceTitle(simSlot);
+ data.screenTitle = mContext.getString(R.string.about_settings);
+ data.keywords = mContext.getString(keywordId).toString();
+ rawData.add(data);
+ }
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index b17afa5..71d56ae 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -30,6 +30,11 @@
public interface PowerUsageFeatureProvider {
/**
+ * Check whether the battery usage button is enabled in the battery page
+ */
+ boolean isBatteryUsageEnabled(Context context);
+
+ /**
* Check whether location setting is enabled
*/
boolean isLocationSettingEnabled(String[] packages);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index 856f86a..932b35d 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -66,6 +66,11 @@
}
@Override
+ public boolean isBatteryUsageEnabled(Context context) {
+ return true;
+ }
+
+ @Override
public boolean isLocationSettingEnabled(String[] packages) {
return false;
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index 0f02d1c..ff139f0 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -84,8 +84,6 @@
new BatteryHistEntry(new ContentValues());
@VisibleForTesting
- static final double PERCENTAGE_OF_TOTAL_THRESHOLD = 1f;
- @VisibleForTesting
static final int SELECTED_INDEX_ALL = BatteryChartViewModel.SELECTED_INDEX_ALL;
@VisibleForTesting
static final String CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER =
@@ -441,7 +439,7 @@
insertAllUsageDiffData(resultMap);
// Compute the apps number before purge. Must put before purgeLowPercentageAndFakeData.
final int countOfAppBeforePurge = getCountOfApps(resultMap);
- purgeLowPercentageAndFakeData(context, resultMap);
+ purgeFakeAndHiddenPackages(context, resultMap);
// Compute the apps number after purge. Must put after purgeLowPercentageAndFakeData.
final int countOfAppAfterPurge = getCountOfApps(resultMap);
if (!isUsageMapValid(resultMap, hourlyBatteryLevelsPerDay)) {
@@ -536,7 +534,7 @@
// Compute the apps number before purge. Must put before purgeLowPercentageAndFakeData.
final int countOfAppBeforePurge = getCountOfApps(resultMap);
- purgeLowPercentageAndFakeData(context, resultMap);
+ purgeFakeAndHiddenPackages(context, resultMap);
// Compute the apps number after purge. Must put after purgeLowPercentageAndFakeData.
final int countOfAppAfterPurge = getCountOfApps(resultMap);
@@ -1122,7 +1120,7 @@
}
// Removes low percentage data and fake usage data, which will be zero value.
- private static void purgeLowPercentageAndFakeData(
+ private static void purgeFakeAndHiddenPackages(
final Context context,
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap) {
final Set<CharSequence> backgroundUsageTimeHideList =
@@ -1139,17 +1137,17 @@
if (diffEntryLists == null) {
return;
}
- purgeLowPercentageAndFakeData(
+ purgeFakeAndHiddenPackages(
diffEntryLists.getAppDiffEntryList(), backgroundUsageTimeHideList,
notAllowShowEntryPackages);
- purgeLowPercentageAndFakeData(
+ purgeFakeAndHiddenPackages(
diffEntryLists.getSystemDiffEntryList(), backgroundUsageTimeHideList,
notAllowShowEntryPackages);
});
});
}
- private static void purgeLowPercentageAndFakeData(
+ private static void purgeFakeAndHiddenPackages(
final List<BatteryDiffEntry> entries,
final Set<CharSequence> backgroundUsageTimeHideList,
final CharSequence[] notAllowShowEntryPackages) {
@@ -1157,8 +1155,7 @@
while (iterator.hasNext()) {
final BatteryDiffEntry entry = iterator.next();
final String packageName = entry.getPackageName();
- if (entry.getPercentOfTotal() < PERCENTAGE_OF_TOTAL_THRESHOLD
- || ConvertUtils.FAKE_PACKAGE_NAME.equals(packageName)
+ if (ConvertUtils.FAKE_PACKAGE_NAME.equals(packageName)
|| contains(packageName, notAllowShowEntryPackages)) {
iterator.remove();
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java b/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java
index 5a4f672..4ab1f42 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java
@@ -36,6 +36,8 @@
*/
public class PowerGaugePreference extends AppPreference {
+ private static final double PERCENTAGE_TO_SHOW_THRESHOLD = 1f;
+
private BatteryEntry mInfo;
private BatteryDiffEntry mBatteryDiffEntry;
private CharSequence mContentDescription;
@@ -75,7 +77,8 @@
/** Sets the percent of total. */
public void setPercent(double percentOfTotal) {
- mProgress = Utils.formatPercentage(percentOfTotal, true);
+ mProgress = percentOfTotal < PERCENTAGE_TO_SHOW_THRESHOLD
+ ? "-" : Utils.formatPercentage(percentOfTotal, true);
notifyChanged();
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
index f266492..dea2431 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
@@ -255,6 +255,8 @@
void initPreference() {
mBatteryUsagePreference = findPreference(KEY_BATTERY_USAGE);
mBatteryUsagePreference.setSummary(getString(R.string.advanced_battery_preference_summary));
+ mBatteryUsagePreference.setVisible(
+ mPowerFeatureProvider.isBatteryUsageEnabled(getContext()));
mHelpPreference = findPreference(KEY_BATTERY_ERROR);
mHelpPreference.setVisible(false);
diff --git a/src/com/android/settings/homepage/TopLevelHighlightMixin.java b/src/com/android/settings/homepage/TopLevelHighlightMixin.java
index f361ed6..d9e646f 100644
--- a/src/com/android/settings/homepage/TopLevelHighlightMixin.java
+++ b/src/com/android/settings/homepage/TopLevelHighlightMixin.java
@@ -116,9 +116,14 @@
}
Log.d(TAG, "onCreateAdapter, pref key: " + mCurrentKey);
+
+ // Remove the animator to avoid a RecyclerView crash.
+ RecyclerView recyclerView = topLevelSettings.getListView();
+ recyclerView.setItemAnimator(null);
+
mTopLevelAdapter = new HighlightableTopLevelPreferenceAdapter(
(SettingsHomepageActivity) topLevelSettings.getActivity(), preferenceScreen,
- topLevelSettings.getListView(), mCurrentKey, scrollNeeded);
+ recyclerView, mCurrentKey, scrollNeeded);
return mTopLevelAdapter;
}
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java b/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java
index 4ac52bc..c6a0d75 100644
--- a/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java
+++ b/src/com/android/settings/inputmethod/KeyboardLayoutPickerController.java
@@ -154,6 +154,7 @@
final SwitchPreference pref = new SwitchPreference(mScreen.getContext());
pref.setTitle(layout.getLabel());
pref.setSummary(layout.getCollection());
+ // TODO: Waiting for new API to use a prefix with special number to setKey
pref.setKey(layout.getDescriptor());
mScreen.addPreference(pref);
mPreferenceMap.put(pref, layout);
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutPreference.java b/src/com/android/settings/inputmethod/KeyboardLayoutPreference.java
new file mode 100644
index 0000000..f9f858b
--- /dev/null
+++ b/src/com/android/settings/inputmethod/KeyboardLayoutPreference.java
@@ -0,0 +1,53 @@
+/*
+ * 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.inputmethod;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.R;
+
+public class KeyboardLayoutPreference extends Preference {
+
+ private ImageView mCheckIcon;
+ private boolean mIsMark;
+
+ public KeyboardLayoutPreference(Context context, String layoutName, boolean defaultMark) {
+ super(context);
+ setWidgetLayoutResource(R.layout.preference_check_icon);
+ setTitle(layoutName);
+ mIsMark = defaultMark;
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ mCheckIcon = (ImageView) holder.findViewById(R.id.keyboard_check_icon);
+ setCheckMark(mIsMark);
+ }
+
+ public void setCheckMark(boolean isMark) {
+ if (mCheckIcon != null) {
+ mCheckIcon.setVisibility(isMark ? View.VISIBLE : View.INVISIBLE);
+ mIsMark = isMark;
+ }
+ }
+}
diff --git a/src/com/android/settings/inputmethod/KeyboardPreferenceController.java b/src/com/android/settings/inputmethod/KeyboardPreferenceController.java
index 75351b1..adabec5 100644
--- a/src/com/android/settings/inputmethod/KeyboardPreferenceController.java
+++ b/src/com/android/settings/inputmethod/KeyboardPreferenceController.java
@@ -78,9 +78,9 @@
@Override
public int getAvailabilityStatus() {
- boolean isFeatureOn = FeatureFlagUtils
- .isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
- return isFeatureOn ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI)
+ ? AVAILABLE
+ : CONDITIONALLY_UNAVAILABLE;
}
private void updateSummary() {
diff --git a/src/com/android/settings/inputmethod/KeyboardSettingsPreferenceController.java b/src/com/android/settings/inputmethod/KeyboardSettingsPreferenceController.java
new file mode 100644
index 0000000..3b86c3f
--- /dev/null
+++ b/src/com/android/settings/inputmethod/KeyboardSettingsPreferenceController.java
@@ -0,0 +1,77 @@
+/*
+ * 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.inputmethod;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.util.FeatureFlagUtils;
+
+import androidx.annotation.NonNull;
+import androidx.preference.Preference;
+
+import com.android.settings.Settings.PhysicalKeyboardActivity;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.inputmethod.PhysicalKeyboardFragment.HardKeyboardDeviceInfo;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+import java.util.List;
+
+public class KeyboardSettingsPreferenceController extends BasePreferenceController {
+
+ private Context mContext;
+ private CachedBluetoothDevice mCachedDevice;
+ private Activity mActivity;
+
+ public KeyboardSettingsPreferenceController(Context context, String key) {
+ super(context, key);
+ mContext = context;
+ }
+
+ public void init(@NonNull CachedBluetoothDevice cachedDevice, @NonNull Activity activity) {
+ mCachedDevice = cachedDevice;
+ mActivity = activity;
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
+ intent.setClass(mContext, PhysicalKeyboardActivity.class);
+ intent.putExtra(PhysicalKeyboardFragment.EXTRA_BT_ADDRESS, mCachedDevice.getAddress());
+ mActivity.startActivityForResult(intent, 0);
+ return true;
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ final List<HardKeyboardDeviceInfo> newHardKeyboards =
+ PhysicalKeyboardFragment.getHardKeyboards(mContext);
+ if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI)
+ && !newHardKeyboards.isEmpty()) {
+ for (HardKeyboardDeviceInfo hardKeyboardDeviceInfo : newHardKeyboards) {
+ if (mCachedDevice.getAddress() != null
+ && hardKeyboardDeviceInfo.mBluetoothAddress != null
+ && mCachedDevice.getAddress().equals(
+ hardKeyboardDeviceInfo.mBluetoothAddress)) {
+ return AVAILABLE;
+ }
+ }
+ }
+ return CONDITIONALLY_UNAVAILABLE;
+ }
+}
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java
new file mode 100644
index 0000000..5c0f88f
--- /dev/null
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java
@@ -0,0 +1,165 @@
+/*
+ * 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.inputmethod;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.hardware.input.InputDeviceIdentifier;
+import android.hardware.input.InputManager;
+import android.os.Bundle;
+import android.view.InputDevice;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+
+import com.android.settings.R;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.dashboard.DashboardFragment;
+
+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 InputDeviceIdentifier mInputDeviceIdentifier;
+ private int mInputDeviceId;
+ private Context mContext;
+
+ @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);
+ getActivity().setTitle(title);
+ final PreferenceCategory category = findPreference(PREF_KEY_ENABLED_LOCALES);
+
+ // 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++) {
+ 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
+ pref.setKey(key);
+ pref.setTitle(keyboardLanguageTitle);
+ pref.setSummary(keyboardLanguageSummary);
+ pref.setOnPreferenceClickListener(
+ preference -> {
+ showKeyboardLayoutPicker(
+ keyboardLanguageTitle,
+ keyboardLanguageSummary,
+ mInputDeviceIdentifier);
+ return true;
+ });
+ category.addPreference(pref);
+ }
+ }
+
+ @Override
+ public void onInputDeviceAdded(int deviceId) {
+ // Do nothing.
+ }
+
+ @Override
+ public void onInputDeviceRemoved(int deviceId) {
+ if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
+ getActivity().finish();
+ }
+ }
+
+ @Override
+ public void onInputDeviceChanged(int deviceId) {
+ if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
+ // TODO(b/252816846): Need APIs to update the available keyboards.
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mContext = getContext();
+ mIm = mContext.getSystemService(InputManager.class);
+ mInputDeviceId = -1;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ mIm.registerInputDeviceListener(this, null);
+ final InputDevice inputDevice =
+ mIm.getInputDeviceByDescriptor(mInputDeviceIdentifier.getDescriptor());
+ if (inputDevice == null) {
+ getActivity().finish();
+ return;
+ }
+ mInputDeviceId = inputDevice.getId();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ mIm.unregisterInputDeviceListener(this);
+ mInputDeviceId = -1;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ // TODO(b/252816846): Need APIs to get the available keyboards from Inputmanager.
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.SETTINGS_KEYBOARDS_ENABLED_LOCALES;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.keyboard_settings_enabled_locales_list;
+ }
+
+ private void showKeyboardLayoutPicker(String language, String layout,
+ InputDeviceIdentifier inputDeviceIdentifier) {
+ 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);
+ new SubSettingLauncher(mContext)
+ .setSourceMetricsCategory(getMetricsCategory())
+ .setDestination(NewKeyboardLayoutPickerFragment.class.getName())
+ .setArguments(arguments)
+ .launch();
+ }
+}
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java
new file mode 100644
index 0000000..dc94306
--- /dev/null
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java
@@ -0,0 +1,72 @@
+/*
+ * 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.inputmethod;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.hardware.input.InputDeviceIdentifier;
+import android.os.Bundle;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+
+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 InputDeviceIdentifier inputDeviceIdentifier =
+ arguments.getParcelable(EXTRA_INPUT_DEVICE_IDENTIFIER);
+
+ if (inputDeviceIdentifier == null) {
+ getActivity().finish();
+ }
+ getActivity().setTitle(title);
+ use(NewKeyboardLayoutPickerController.class).initialize(this /*parent*/,
+ inputDeviceIdentifier, layout);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ // TODO: add new SettingsEnums SETTINGS_KEYBOARDS_LAYOUT_PICKER_CONTENT
+ return SettingsEnums.SETTINGS_KEYBOARDS_LAYOUT_PICKER;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ protected int getPreferenceScreenResId() {
+ return R.xml.new_keyboard_layout_picker_fragment;
+ }
+}
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
new file mode 100644
index 0000000..4a598d5
--- /dev/null
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
@@ -0,0 +1,156 @@
+/*
+ * 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.inputmethod;
+
+import android.content.Context;
+import android.hardware.input.InputDeviceIdentifier;
+import android.hardware.input.InputManager;
+import android.hardware.input.KeyboardLayout;
+import android.view.InputDevice;
+
+import androidx.fragment.app.Fragment;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.core.BasePreferenceController;
+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;
+
+public class NewKeyboardLayoutPickerController extends BasePreferenceController implements
+ InputManager.InputDeviceListener, LifecycleObserver, OnStart, OnStop {
+ private final InputManager mIm;
+ private final Map<KeyboardLayoutPreference, KeyboardLayout> mPreferenceMap;
+
+ private Fragment mParent;
+ private int mInputDeviceId;
+ private InputDeviceIdentifier mInputDeviceIdentifier;
+ private KeyboardLayout[] mKeyboardLayouts;
+ private PreferenceScreen mScreen;
+ private String mPreviousSelection;
+ private String mLayout;
+
+ public NewKeyboardLayoutPickerController(Context context, String key) {
+ super(context, key);
+ mIm = context.getSystemService(InputManager.class);
+ mInputDeviceId = -1;
+ mPreferenceMap = new HashMap<>();
+ }
+
+ public void initialize(Fragment parent, InputDeviceIdentifier inputDeviceIdentifier,
+ String layout) {
+ mLayout = layout;
+ mParent = parent;
+ mInputDeviceIdentifier = inputDeviceIdentifier;
+ mKeyboardLayouts = mIm.getKeyboardLayoutsForInputDevice(mInputDeviceIdentifier);
+ Arrays.sort(mKeyboardLayouts);
+ }
+
+ @Override
+ public void onStart() {
+ mIm.registerInputDeviceListener(this, null);
+ final InputDevice inputDevice =
+ mIm.getInputDeviceByDescriptor(mInputDeviceIdentifier.getDescriptor());
+ if (inputDevice == null) {
+ mParent.getActivity().finish();
+ return;
+ }
+ mInputDeviceId = inputDevice.getId();
+ }
+
+ @Override
+ public void onStop() {
+ mIm.unregisterInputDeviceListener(this);
+ mInputDeviceId = -1;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mScreen = screen;
+ createPreferenceHierarchy();
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+
+ if (!(preference instanceof KeyboardLayoutPreference)) {
+ return false;
+ }
+
+ 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)
+ if (mPreviousSelection != null && !mPreviousSelection.equals(preference.getKey())) {
+ KeyboardLayoutPreference preSelectedPref = mScreen.findPreference(mPreviousSelection);
+ pref.setCheckMark(true);
+ preSelectedPref.setCheckMark(false);
+ }
+ mPreviousSelection = preference.getKey();
+ return true;
+ }
+
+ @Override
+ public void onInputDeviceAdded(int deviceId) {
+ // Do nothing.
+ }
+
+ @Override
+ public void onInputDeviceRemoved(int deviceId) {
+ if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
+ mParent.getActivity().finish();
+ }
+ }
+
+ @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.
+ }
+
+ private void createPreferenceHierarchy() {
+ for (KeyboardLayout layout : mKeyboardLayouts) {
+ final KeyboardLayoutPreference pref;
+ if (mLayout.equals(layout.getLabel())) {
+ pref = new KeyboardLayoutPreference(mScreen.getContext(), layout.getLabel(), true);
+ mPreviousSelection = layout.getLabel();
+ } 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());
+ mScreen.addPreference(pref);
+ mPreferenceMap.put(pref, layout);
+ }
+ }
+}
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java
new file mode 100644
index 0000000..c2f41a2
--- /dev/null
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerFragment.java
@@ -0,0 +1,61 @@
+/*
+ * 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.inputmethod;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.fragment.app.Fragment;
+
+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
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ mFragmentView = (ViewGroup) inflater.inflate(
+ R.layout.keyboard_layout_picker, container, false);
+ getActivity().getSupportFragmentManager()
+ .beginTransaction()
+ .replace(R.id.keyboard_layout_title, new NewKeyboardLayoutPickerTitle())
+ .commit();
+
+ NewKeyboardLayoutPickerContent fragment = new NewKeyboardLayoutPickerContent();
+ fragment.setArguments(getArguments());
+ getActivity().getSupportFragmentManager()
+ .beginTransaction()
+ .replace(R.id.keyboard_layouts, fragment)
+ .commit();
+
+ return mFragmentView;
+ }
+}
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerTitle.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerTitle.java
new file mode 100644
index 0000000..abcad27
--- /dev/null
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerTitle.java
@@ -0,0 +1,48 @@
+/*
+ * 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.inputmethod;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+
+public class NewKeyboardLayoutPickerTitle extends SettingsPreferenceFragment {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.new_keyboard_layout_picker_title);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ // TODO: add new SettingsEnums SETTINGS_KEYBOARDS_LAYOUT_PICKER_TITLE
+ return SettingsEnums.SETTINGS_KEYBOARDS_LAYOUT_PICKER;
+ }
+
+ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider(R.xml.new_keyboard_layout_picker_title) {
+ @Override
+ protected boolean isPageSearchEnabled(Context context) {
+ return false;
+ }
+ };
+}
diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
index d7a208c..38ea840 100644
--- a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
+++ b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
@@ -33,6 +33,7 @@
import android.provider.SearchIndexableResource;
import android.provider.Settings.Secure;
import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
import android.view.InputDevice;
import androidx.preference.Preference;
@@ -45,6 +46,7 @@
import com.android.settings.R;
import com.android.settings.Settings;
import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.core.SubSettingLauncher;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.utils.ThreadUtils;
@@ -52,7 +54,9 @@
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
@@ -60,7 +64,7 @@
implements InputManager.InputDeviceListener,
KeyboardLayoutDialogFragment.OnSetupKeyboardLayoutsListener {
- private static final String KEYBOARD_ASSISTANCE_CATEGORY = "keyboard_assistance_category";
+ private static final String KEYBOARD_OPTIONS_CATEGORY = "keyboard_options_category";
private static final String SHOW_VIRTUAL_KEYBOARD_SWITCH = "show_virtual_keyboard_switch";
private static final String KEYBOARD_SHORTCUTS_HELPER = "keyboard_shortcuts_helper";
@@ -74,17 +78,25 @@
private SwitchPreference mShowVirtualKeyboardSwitch;
private Intent mIntentWaitingForResult;
+ private boolean mIsNewKeyboardSettings;
+
+ static final String EXTRA_BT_ADDRESS = "extra_bt_address";
+ private String mBluetoothAddress;
@Override
public void onCreatePreferences(Bundle bundle, String s) {
Activity activity = Preconditions.checkNotNull(getActivity());
+ mBluetoothAddress = activity.getIntent().getStringExtra(EXTRA_BT_ADDRESS);
addPreferencesFromResource(R.xml.physical_keyboard_settings);
mIm = Preconditions.checkNotNull(activity.getSystemService(InputManager.class));
mKeyboardAssistanceCategory = Preconditions.checkNotNull(
- (PreferenceCategory) findPreference(KEYBOARD_ASSISTANCE_CATEGORY));
+ (PreferenceCategory) findPreference(KEYBOARD_OPTIONS_CATEGORY));
mShowVirtualKeyboardSwitch = Preconditions.checkNotNull(
(SwitchPreference) mKeyboardAssistanceCategory.findPreference(
SHOW_VIRTUAL_KEYBOARD_SWITCH));
+ mIsNewKeyboardSettings = FeatureFlagUtils.isEnabled(
+ getContext(), FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
+ // TODO(b/247080921): Support shortcuts list & modifier keys
}
@Override
@@ -164,17 +176,55 @@
preferenceScreen.addPreference(category);
for (HardKeyboardDeviceInfo hardKeyboardDeviceInfo : newHardKeyboards) {
+
+ // if user go into this page from Connected devices entry, we should distinguish the
+ // user-selected keyboard from all enabled keyboards.
+ if (mBluetoothAddress != null
+ && !mBluetoothAddress.equals(hardKeyboardDeviceInfo.mBluetoothAddress)) {
+ continue;
+ }
+
// TODO(yukawa): Consider using com.android.settings.widget.GearPreference
final Preference pref = new Preference(getPrefContext());
pref.setTitle(hardKeyboardDeviceInfo.mDeviceName);
- pref.setSummary(hardKeyboardDeviceInfo.mLayoutLabel);
- pref.setOnPreferenceClickListener(preference -> {
- showKeyboardLayoutDialog(hardKeyboardDeviceInfo.mDeviceIdentifier);
- return true;
- });
+ 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]);
+ StringBuilder result = new StringBuilder(summary);
+ for (int i = 1; i < keyboardLanguages.length; i++) {
+ result.append(", ").append(keyboardMap.get(keyboardLanguages[i]));
+ }
+ pref.setSummary(result.toString());
+ } else {
+ pref.setSummary(hardKeyboardDeviceInfo.mLayoutLabel);
+ }
+ pref.setOnPreferenceClickListener(
+ preference -> {
+ showEnabledLocalesKeyboardLayoutList(
+ hardKeyboardDeviceInfo.mDeviceName,
+ hardKeyboardDeviceInfo.mDeviceIdentifier);
+ return true;
+ });
+ } else {
+ pref.setSummary(hardKeyboardDeviceInfo.mLayoutLabel);
+ pref.setOnPreferenceClickListener(
+ preference -> {
+ showKeyboardLayoutDialog(hardKeyboardDeviceInfo.mDeviceIdentifier);
+ return true;
+ });
+ }
category.addPreference(pref);
}
-
mKeyboardAssistanceCategory.setOrder(1);
preferenceScreen.addPreference(mKeyboardAssistanceCategory);
updateShowVirtualKeyboardSwitch();
@@ -187,6 +237,21 @@
fragment.show(getActivity().getSupportFragmentManager(), "keyboardLayout");
}
+ 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,
+ inputDeviceIdentifier);
+ arguments.putString(NewKeyboardLayoutEnabledLocalesFragment.EXTRA_KEYBOARD_DEVICE_NAME,
+ keyboardName);
+ new SubSettingLauncher(getContext())
+ .setSourceMetricsCategory(getMetricsCategory())
+ .setDestination(NewKeyboardLayoutEnabledLocalesFragment.class.getName())
+ .setArguments(arguments)
+ .launch();
+ }
+
private void registerShowVirtualKeyboardSettingsObserver() {
unregisterShowVirtualKeyboardSettingsObserver();
getActivity().getContentResolver().registerContentObserver(
@@ -277,7 +342,10 @@
continue;
}
keyboards.add(new HardKeyboardDeviceInfo(
- device.getName(), device.getIdentifier(), getLayoutLabel(device, context, im)));
+ device.getName(),
+ device.getIdentifier(),
+ getLayoutLabel(device, context, im),
+ device.getBluetoothAddress()));
}
// We intentionally don't reuse Comparator because Collator may not be thread-safe.
@@ -304,14 +372,18 @@
public final InputDeviceIdentifier mDeviceIdentifier;
@NonNull
public final String mLayoutLabel;
+ @Nullable
+ public final String mBluetoothAddress;
public HardKeyboardDeviceInfo(
@Nullable String deviceName,
@NonNull InputDeviceIdentifier deviceIdentifier,
- @NonNull String layoutLabel) {
+ @NonNull String layoutLabel,
+ @Nullable String bluetoothAddress) {
mDeviceName = TextUtils.emptyIfNull(deviceName);
mDeviceIdentifier = deviceIdentifier;
mLayoutLabel = layoutLabel;
+ mBluetoothAddress = bluetoothAddress;
}
@Override
@@ -331,6 +403,9 @@
if (!TextUtils.equals(mLayoutLabel, that.mLayoutLabel)) {
return false;
}
+ if (!TextUtils.equals(mBluetoothAddress, that.mBluetoothAddress)) {
+ return false;
+ }
return true;
}
diff --git a/src/com/android/settings/wifi/WifiUtils.java b/src/com/android/settings/wifi/WifiUtils.java
index a9010ac..68d8beb 100644
--- a/src/com/android/settings/wifi/WifiUtils.java
+++ b/src/com/android/settings/wifi/WifiUtils.java
@@ -96,7 +96,7 @@
* @return true if Settings cannot modify the config due to lockDown.
*/
public static boolean isNetworkLockedDown(Context context, WifiConfiguration config) {
- if (config == null) {
+ if (context == null || config == null) {
return false;
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
index fae61d6..31e0782 100644
--- a/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
@@ -54,6 +54,9 @@
@Mock
private PreferenceScreen mPreferenceScreen;
+ @Mock
+ private PreviewSizeSeekBarController.ProgressInteractionListener mInteractionListener;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -65,6 +68,8 @@
mSeekBarPreference = spy(new LabeledSeekBarPreference(mContext, /* attrs= */ null));
when(mPreferenceScreen.findPreference(anyString())).thenReturn(mSeekBarPreference);
+
+ mSeekBarController.setInteractionListener(mInteractionListener);
}
@Test
@@ -98,4 +103,12 @@
assertThat(mSeekBarPreference.getProgress()).isEqualTo(defaultProgress);
}
+
+ @Test
+ public void resetState_verifyOnProgressChanged() {
+ mSeekBarController.displayPreference(mPreferenceScreen);
+ mSeekBarController.resetState();
+
+ verify(mInteractionListener).onProgressChanged();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java b/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java
index 4813c80..7df24f1 100644
--- a/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/TextReadingPreferenceFragmentForSetupWizardTest.java
@@ -20,6 +20,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -27,11 +28,13 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
+import androidx.fragment.app.FragmentActivity;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settingslib.widget.LayoutPreference;
+import com.google.android.setupcompat.template.FooterBarMixin;
import com.google.android.setupdesign.GlifPreferenceLayout;
import org.junit.Before;
@@ -50,8 +53,16 @@
@Rule
public final MockitoRule mMockito = MockitoJUnit.rule();
+
@Mock
private GlifPreferenceLayout mGlifLayoutView;
+
+ @Mock
+ private FooterBarMixin mFooterBarMixin;
+
+ @Mock
+ private FragmentActivity mActivity;
+
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
private TextReadingPreferenceFragmentForSetupWizard mFragment;
@@ -61,13 +72,14 @@
mFragment = spy(new TextReadingPreferenceFragmentForSetupWizard());
final LayoutPreference resetPreference =
new LayoutPreference(mContext, R.layout.accessibility_text_reading_reset_button);
+ doReturn(mContext).when(mFragment).getContext();
doReturn(resetPreference).when(mFragment).findPreference(RESET_KEY);
+ doReturn(mFooterBarMixin).when(mGlifLayoutView).getMixin(FooterBarMixin.class);
}
@Test
public void setHeaderText_onViewCreated_verifyAction() {
final String title = "title";
- doReturn(mContext).when(mFragment).getContext();
doReturn(title).when(mContext).getString(
R.string.accessibility_text_reading_options_title);
@@ -86,4 +98,21 @@
public void getHelpResource_shouldNotHaveHelpResource() {
assertThat(mFragment.getHelpResource()).isEqualTo(0);
}
+
+ @Test
+ public void onViewCreated_verifySetSecondaryButton() {
+ mFragment.onViewCreated(mGlifLayoutView, null);
+
+ verify(mFooterBarMixin).setSecondaryButton(any());
+ }
+
+ @Test
+ public void onViewCreated_verifySetPrimaryButton() {
+ doReturn(mActivity).when(mFragment).getActivity();
+ doReturn("setupwizard").when(mActivity).getCallingPackage();
+
+ mFragment.onViewCreated(mGlifLayoutView, null);
+
+ verify(mFooterBarMixin).setPrimaryButton(any());
+ }
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/TextReadingResetControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/TextReadingResetControllerTest.java
index 231c9ca..d5b138a 100644
--- a/tests/robotests/src/com/android/settings/accessibility/TextReadingResetControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/TextReadingResetControllerTest.java
@@ -16,6 +16,8 @@
package com.android.settings.accessibility;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -70,4 +72,20 @@
verify(mResetPreference).setOnResetClickListener(any(View.OnClickListener.class));
}
+
+ @Test
+ public void setVisibleAsFalse_preferenceInvisible() {
+ mResetController.setVisible(false);
+ mResetController.displayPreference(mPreferenceScreen);
+
+ assertThat(mResetPreference.isVisible()).isFalse();
+ }
+
+ @Test
+ public void setVisibleAsTrue_preferenceVisible() {
+ mResetController.setVisible(true);
+ mResetController.displayPreference(mPreferenceScreen);
+
+ assertThat(mResetPreference.isVisible()).isTrue();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
index f9d4445..596f3b2 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
@@ -18,7 +18,6 @@
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
-import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UNKNOWN;
import static com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling.KEY_STATE_PREVIOUS_ROTATION;
import static com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling.SFPS_STAGE_NO_ANIMATION;
@@ -31,7 +30,6 @@
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -52,9 +50,6 @@
import android.os.Vibrator;
import android.view.Display;
import android.view.Surface;
-import android.widget.TextView;
-
-import androidx.annotation.Nullable;
import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
@@ -106,42 +101,6 @@
}
@Test
- public void fingerprintEnrollHelp_shouldShowHelpText() {
- initializeActivityFor(TYPE_UNKNOWN);
- TestFingerprintEnrollSidecar sidecar = new TestFingerprintEnrollSidecar();
- Resources resources = mock(Resources.class);
- doReturn(resources).when(mContext).getResources();
- when(resources.getIntArray(R.array.fingerprint_acquired_ignore_list))
- .thenReturn(new int[]{3});
-
- sidecar.setListener(mActivity);
- sidecar.onAttach(mActivity);
- sidecar.mEnrollmentCallback.onEnrollmentHelp(5,
- "Help message should be displayed.");
-
- TextView errorText = mActivity.findViewById(R.id.error_text);
- assertThat(errorText.getText()).isEqualTo("Help message should be displayed.");
- }
-
- @Test
- public void fingerprintEnrollHelp_shouldNotShowHelpText() {
- initializeActivityFor(TYPE_UNKNOWN);
- TestFingerprintEnrollSidecar sidecar = new TestFingerprintEnrollSidecar();
- Resources resources = mock(Resources.class);
- doReturn(resources).when(mContext).getResources();
- when(resources.getIntArray(R.array.fingerprint_acquired_ignore_list))
- .thenReturn(new int[]{3});
-
- sidecar.setListener(mActivity);
- sidecar.onAttach(mActivity);
- sidecar.mEnrollmentCallback.onEnrollmentHelp(3,
- "Help message should not be displayed.");
-
- TextView errorText = mActivity.findViewById(R.id.error_text);
- assertThat(errorText.getText()).isEqualTo("");
- }
-
- @Test
public void fingerprintUdfpsEnrollSuccessProgress_shouldNotVibrate() {
initializeActivityFor(TYPE_UDFPS_OPTICAL);
@@ -389,12 +348,4 @@
return callbackCaptor.getValue();
}
-
- private class TestFingerprintEnrollSidecar extends FingerprintEnrollSidecar {
- @Nullable
- @Override
- public Context getContext() {
- return mContext;
- }
- }
}
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/MessageDisplayControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/MessageDisplayControllerTest.java
new file mode 100644
index 0000000..0fa0918
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/MessageDisplayControllerTest.java
@@ -0,0 +1,219 @@
+/*
+ * 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.fingerprint;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Handler;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowLooper;
+
+import java.time.Clock;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(RobolectricTestRunner.class)
+public class MessageDisplayControllerTest {
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
+ private static final long START_TIME = 0L;
+ private static final int HELP_ID = 0;
+ private static final String HELP_MESSAGE = "Default Help Message";
+ private static final int REMAINING = 5;
+ private static final int HELP_MINIMUM_DISPLAY_TIME = 300;
+ private static final int PROGRESS_MINIMUM_DISPLAY_TIME = 250;
+ private static final int COLLECT_TIME = 100;
+
+ private MessageDisplayController mMessageDisplayController;
+ @Mock
+ private FingerprintManager.EnrollmentCallback mEnrollmentCallback;
+ @Mock
+ private Clock mClock;
+
+ @Before
+ public void setup() {
+ mMessageDisplayController = new MessageDisplayController(new Handler(), mEnrollmentCallback,
+ mClock,
+ HELP_MINIMUM_DISPLAY_TIME, /* progressPriorityOverHelp */
+ PROGRESS_MINIMUM_DISPLAY_TIME, /* prioritizeAcquireMessages */
+ false, false, COLLECT_TIME);
+ }
+
+ private void setMessageDisplayController(boolean progressPriorityOverHelp,
+ boolean prioritizeAcquireMessages) {
+ mMessageDisplayController = new MessageDisplayController(new Handler(), mEnrollmentCallback,
+ mClock, HELP_MINIMUM_DISPLAY_TIME, PROGRESS_MINIMUM_DISPLAY_TIME,
+ progressPriorityOverHelp, prioritizeAcquireMessages, COLLECT_TIME);
+ }
+
+ @Test
+ public void showsHelpMessageAfterCollectTime() {
+ when(mClock.millis()).thenReturn(START_TIME);
+
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ verifyNoMoreInteractions(mEnrollmentCallback);
+ }
+
+ @Test
+ public void showsProgressMessageAfterCollectTime() {
+ when(mClock.millis()).thenReturn(START_TIME);
+
+ mMessageDisplayController.onEnrollmentProgress(REMAINING);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+ verifyNoMoreInteractions(mEnrollmentCallback);
+ }
+
+ @Test
+ public void helpDisplayedForMinimumDisplayTime() {
+ when(mClock.millis()).thenReturn(START_TIME);
+
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+
+ mMessageDisplayController.onEnrollmentProgress(REMAINING);
+
+ verifyNoMoreInteractions(mEnrollmentCallback);
+
+ when(mClock.millis()).thenReturn((long) (HELP_MINIMUM_DISPLAY_TIME + COLLECT_TIME));
+ ShadowLooper.idleMainLooper(HELP_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+ }
+
+ @Test
+ public void progressDisplayedForMinimumDisplayTime() {
+ when(mClock.millis()).thenReturn(START_TIME);
+
+ mMessageDisplayController.onEnrollmentProgress(REMAINING);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+
+ verifyNoMoreInteractions(mEnrollmentCallback);
+
+ when(mClock.millis()).thenReturn((long) (COLLECT_TIME + PROGRESS_MINIMUM_DISPLAY_TIME));
+ ShadowLooper.idleMainLooper(PROGRESS_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ }
+
+ @Test
+ public void prioritizeHelpMessage_thenShowProgress() {
+ when(mClock.millis()).thenReturn(START_TIME);
+
+ mMessageDisplayController.onEnrollmentProgress(REMAINING);
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ verifyNoMoreInteractions(mEnrollmentCallback);
+
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) (COLLECT_TIME + HELP_MINIMUM_DISPLAY_TIME));
+ ShadowLooper.idleMainLooper(HELP_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+ }
+
+ @Test
+ public void prioritizeProgressOverHelp() {
+ when(mClock.millis()).thenReturn(START_TIME);
+ setMessageDisplayController(true /* progressPriorityOverHelp */,
+ false /* prioritizeAcquireMessages */);
+
+ mMessageDisplayController.onEnrollmentProgress(REMAINING);
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+ verifyNoMoreInteractions(mEnrollmentCallback);
+ }
+
+ @Test
+ public void prioritizeHelpMessageByCount() {
+ String newHelpMessage = "New message";
+ when(mClock.millis()).thenReturn(START_TIME);
+ setMessageDisplayController(false /* progressPriorityOverHelp */,
+ true /* prioritizeAcquireMessages */);
+
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, newHelpMessage);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ verifyNoMoreInteractions(mEnrollmentCallback);
+ }
+
+ @Test
+ public void ignoreSameProgress() {
+ int progressChange = REMAINING - 1;
+ when(mClock.millis()).thenReturn(START_TIME);
+ setMessageDisplayController(true /* progressPriorityOverHelp */,
+ false /* prioritizeAcquireMessages */);
+
+ mMessageDisplayController.onEnrollmentProgress(REMAINING);
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) COLLECT_TIME);
+ ShadowLooper.idleMainLooper(COLLECT_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentProgress(REMAINING);
+ verifyNoMoreInteractions(mEnrollmentCallback);
+
+ mMessageDisplayController.onEnrollmentProgress(REMAINING);
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) (COLLECT_TIME + PROGRESS_MINIMUM_DISPLAY_TIME));
+ ShadowLooper.idleMainLooper(PROGRESS_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+
+ mMessageDisplayController.onEnrollmentProgress(progressChange);
+ mMessageDisplayController.onEnrollmentHelp(HELP_ID, HELP_MESSAGE);
+ when(mClock.millis()).thenReturn((long) (COLLECT_TIME + PROGRESS_MINIMUM_DISPLAY_TIME
+ + HELP_MINIMUM_DISPLAY_TIME));
+ ShadowLooper.idleMainLooper(HELP_MINIMUM_DISPLAY_TIME, TimeUnit.MILLISECONDS);
+
+ verify(mEnrollmentCallback).onEnrollmentProgress(progressChange);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerTest.java
index 9d4956d..eea07fe 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusPreferenceControllerTest.java
@@ -16,6 +16,8 @@
package com.android.settings.deviceinfo.simstatus;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -26,6 +28,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.os.UserManager;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -37,6 +40,7 @@
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.search.SearchIndexableRaw;
import java.util.ArrayList;
import java.util.List;
@@ -62,6 +66,10 @@
@Mock
private PreferenceScreen mScreen;
@Mock
+ private SubscriptionManager mSubscriptionManager;
+ @Mock
+ private SubscriptionInfo mSubscriptionInfo;
+ @Mock
private TelephonyManager mTelephonyManager;
@Mock
private UserManager mUserManager;
@@ -85,6 +93,8 @@
when(mResources.getBoolean(R.bool.config_show_sim_info)).thenReturn(true);
mockService(Context.TELEPHONY_SERVICE, TelephonyManager.class, mTelephonyManager);
+ mockService(Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class,
+ mSubscriptionManager);
mockService(Context.USER_SERVICE, UserManager.class, mUserManager);
final List<Preference> preferencePool = new ArrayList<Preference>();
@@ -96,6 +106,10 @@
public Preference createNewPreference(Context context) {
return preferencePool.remove(0);
}
+ @Override
+ public int getSimSlotIndex() {
+ return 0;
+ }
});
doReturn(BasePreferenceController.AVAILABLE).when(mController).getAvailabilityStatus();
when(mScreen.getContext()).thenReturn(mContext);
@@ -163,6 +177,47 @@
verify(mFragment).getChildFragmentManager();
}
+ @Test
+ public void updateDynamicRawDataToIndex_notAddToSearch_emptySimSlot() {
+ doReturn(null).when(mSubscriptionManager).getActiveSubscriptionInfoList();
+ SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
+ List<SearchIndexableRaw> rawData = new ArrayList<SearchIndexableRaw>();
+
+ mController.init(mFragment, slotSimStatus);
+ mController.updateDynamicRawDataToIndex(rawData);
+
+ assertThat(rawData.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void updateDynamicRawDataToIndex_addToSearch_simInSimSlot() {
+ doReturn(false).when(mSubscriptionInfo).isEmbedded();
+ doReturn(List.of(mSubscriptionInfo)).when(mSubscriptionManager)
+ .getActiveSubscriptionInfoList();
+ SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
+ List<SearchIndexableRaw> rawData = new ArrayList<SearchIndexableRaw>();
+
+ mController.init(mFragment, slotSimStatus);
+ mController.updateDynamicRawDataToIndex(rawData);
+
+ assertThat(rawData.size()).isEqualTo(1);
+ }
+
+ @Test
+ public void updateDynamicRawDataToIndex_addEsimToSearch_esimInSimSlot() {
+ doReturn(true).when(mSubscriptionInfo).isEmbedded();
+ doReturn(List.of(mSubscriptionInfo)).when(mSubscriptionManager)
+ .getActiveSubscriptionInfoList();
+ SlotSimStatus slotSimStatus = new SlotSimStatus(mContext);
+ List<SearchIndexableRaw> rawData = new ArrayList<SearchIndexableRaw>();
+
+ mController.init(mFragment, slotSimStatus);
+ mController.updateDynamicRawDataToIndex(rawData);
+
+ assertThat(rawData.size()).isEqualTo(1);
+ assertThat(rawData.get(0).keywords.contains("eid")).isTrue();
+ }
+
private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {
when(mContext.getSystemServiceName(serviceClass)).thenReturn(serviceName);
when(mContext.getSystemService(serviceName)).thenReturn(service);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
index 648685a..ab61abc 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
@@ -63,6 +63,11 @@
}
@Test
+ public void testIsBatteryUsageEnabled_returnFalse() {
+ assertThat(mPowerFeatureProvider.isBatteryUsageEnabled(mContext)).isTrue();
+ }
+
+ @Test
public void testIsTypeSystem_uidRoot_returnTrue() {
assertThat(mPowerFeatureProvider.isTypeSystem(Process.ROOT_UID, null)).isTrue();
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java
index 5d599fe..e9573f1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java
@@ -104,4 +104,18 @@
assertThat(mPreferenceViewHolder.findViewById(android.R.id.title).getContentDescription())
.isEqualTo(CONTENT_DESCRIPTION);
}
+
+ @Test
+ public void setPercent_greaterThanThreshold_showNumber() {
+ mPowerGaugePreference.setPercent(99.5);
+
+ assertThat(mPowerGaugePreference.getPercent()).isEqualTo("100%");
+ }
+
+ @Test
+ public void setPercent_lessThanThreshold_showBar() {
+ mPowerGaugePreference.setPercent(0.95);
+
+ assertThat(mPowerGaugePreference.getPercent()).isEqualTo("-");
+ }
}