DO NOT MERGE - Merge qt-qpr1-dev-plus-aosp-without-vendor (6129114) into stage-aosp-master
Bug: 146167222 Change-Id: I77344517b74a2192af49a3f8956d8756b81741d9
This commit is contained in:
@@ -936,6 +936,24 @@
|
||||
android:value="true" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="Settings$DarkThemeSettingsActivity"
|
||||
android:label="@string/dark_ui_auto_mode_title"
|
||||
android:enabled="true">
|
||||
<intent-filter android:priority="32">
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="com.android.settings.SHORTCUT" />
|
||||
</intent-filter>
|
||||
<intent-filter android:priority="1">
|
||||
<action android:name="android.settings.DARK_THEME_SETTINGS" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
|
||||
android:value="com.android.settings.display.darkmode.DarkModeSettingsFragment" />
|
||||
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
|
||||
android:value="true" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="Settings$NightDisplaySuggestionActivity"
|
||||
android:enabled="@*android:bool/config_nightDisplayAvailable"
|
||||
|
@@ -51,8 +51,9 @@
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:id="@+id/bt_battery_icon"
|
||||
android:layout_width="13dp"
|
||||
android:layout_height="20dp"/>
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"/>
|
||||
<TextView
|
||||
android:id="@+id/bt_battery_summary"
|
||||
style="@style/TextAppearance.EntityHeaderSummary"
|
||||
|
@@ -44,16 +44,10 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:minLines="2"
|
||||
android:minLines="3"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"/>
|
||||
android:textColor="?android:attr/textColorPrimary"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/summary2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"/>
|
||||
android:textColor="?android:attr/textColorPrimary"/>
|
||||
</LinearLayout>
|
||||
|
||||
<com.android.settings.fuelgauge.BatteryMeterView
|
||||
|
40
res/layout/dark_ui_activation_button.xml
Normal file
40
res/layout/dark_ui_activation_button.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 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:minHeight="?android:attr/listPreferredItemHeight">
|
||||
|
||||
<Button
|
||||
android:id="@+id/dark_ui_turn_on_button"
|
||||
style="@style/ActionPrimaryButton"
|
||||
android:layout_marginStart="@dimen/screen_margin_sides"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/dark_ui_turn_off_button"
|
||||
style="@style/ActionSecondaryButton"
|
||||
android:layout_marginStart="@dimen/screen_margin_sides"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical" />
|
||||
|
||||
</LinearLayout>
|
@@ -124,9 +124,9 @@
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
<TextView
|
||||
android:id="@+id/face_enroll_introduction_footer_part_2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/security_settings_face_enroll_introduction_footer_part_2"/>
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@@ -100,6 +100,14 @@
|
||||
<item>1800000</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Dark theme scheduling preferences [CHAR LIMIT=NONE] -->
|
||||
<string-array name="dark_ui_scheduler_preference_titles">
|
||||
<!-- 1: None -->
|
||||
<item>@string/dark_ui_auto_mode_never</item>
|
||||
<!-- 2: Auto -->
|
||||
<item>@string/dark_ui_auto_mode_auto</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Security settings. The delay after screen is turned off until device locks.
|
||||
These are shown in a list dialog. -->
|
||||
<string-array name="lock_after_timeout_entries">
|
||||
|
@@ -417,4 +417,7 @@
|
||||
|
||||
<!-- "Show work policy info" intent action. TODO(b/134391103): Replace with final SystemAPI intent when it's available. -->
|
||||
<string name="config_work_policy_info_intent_action" translatable="false"/>
|
||||
|
||||
<!-- RTT setting intent action -->
|
||||
<string name="config_rtt_setting_intent_action" translatable="false"></string>
|
||||
</resources>
|
||||
|
@@ -414,4 +414,11 @@
|
||||
|
||||
<!-- System navigation settings illustration height -->
|
||||
<dimen name="system_navigation_illustration_height">320dp</dimen>
|
||||
|
||||
<!-- Header title size of advanced bluetooth device -->
|
||||
<dimen name="advanced_bluetooth_header_title_text_size">16sp</dimen>
|
||||
|
||||
<!-- Battery meter icon size of advanced bluetooth device -->
|
||||
<dimen name="advanced_bluetooth_battery_meter_width">7.8dp</dimen>
|
||||
<dimen name="advanced_bluetooth_battery_meter_height">13dp</dimen>
|
||||
</resources>
|
||||
|
@@ -827,7 +827,9 @@
|
||||
<!-- Button text in face settings which lets the user enroll their face [CHAR LIMIT=40] -->
|
||||
<string name="security_settings_face_settings_enroll">Set up face unlock</string>
|
||||
<!-- Text shown in face settings explaining what your face can be used for. [CHAR LIMIT=NONE] -->
|
||||
<string name="security_settings_face_settings_footer">Use face unlock to unlock your device, sign in to apps, and confirm payments.\n\nKeep in mind:\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face, even if your eyes are closed.\n\nYour phone can be unlocked by someone who looks a lot like you, say, an identical sibling.</string>
|
||||
<string name="security_settings_face_settings_footer">Use face unlock to unlock your device, sign in to apps, and confirm payments.\n\nKeep in mind:\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face while your eyes are open.\n\nYour phone can be unlocked by someone who looks a lot like you, say, an identical sibling.</string>
|
||||
<!-- Text shown in face settings explaining what your face can be used for. Used when attention checking is not supported. [CHAR LIMIT=NONE] -->
|
||||
<string name="security_settings_face_settings_footer_attention_not_supported">Use face unlock to unlock your device, sign in to apps, and confirm payments.\n\nKeep in mind:\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face, even if your eyes are closed.\n\nYour phone can be unlocked by someone who looks a lot like you, say, an identical sibling.</string>
|
||||
<!-- Dialog title shown when the user removes an enrollment [CHAR LIMIT=35] -->
|
||||
<string name="security_settings_face_settings_remove_dialog_title">Delete face data?</string>
|
||||
<!-- Dialog contents shown when the user removes an enrollment [CHAR LIMIT=NONE] -->
|
||||
@@ -2757,6 +2759,40 @@
|
||||
<!-- Night display slice screen, subtitle of intensity setting when night light is off. [CHAR LIMIT=30] -->
|
||||
<string name="night_display_not_currently_on">Night Light not currently on</string>
|
||||
|
||||
<!-- Dark ui screen-->
|
||||
<!-- Display settings screen, activation button action for manual mode. [CHAR LIMIT=40] -->
|
||||
<string name="dark_ui_activation_on_manual">Turn on now</string>
|
||||
<!-- Display settings screen, deactivation button action for manual mode. [CHAR LIMIT=40] -->
|
||||
<string name="dark_ui_activation_off_manual">Turn off now</string>
|
||||
<!-- Display settings screen, activation button action for sunset-to-sunrise schedule [CHAR LIMIT=40] -->
|
||||
<string name="dark_ui_activation_on_auto">Turn on until sunrise</string>
|
||||
<!-- Display settings screen, deactivation button action for sunset-to-sunrise schedule [CHAR LIMIT=40] -->
|
||||
<string name="dark_ui_activation_off_auto">Turn off until sunset</string>
|
||||
<!-- Dark UI screen, setting option name to enable Dark UI [CHAR LIMIT=30] -->
|
||||
<string name="dark_ui_title">Dark Mode</string>
|
||||
<!-- Dark UI screen, setting option name to configure whether Dark UI turn on/off automatically. [CHAR LIMIT=30] -->
|
||||
<string name="dark_ui_auto_mode_title">Schedule</string>
|
||||
<!-- Dark UI screen, setting option value for Dark UI to *never* turn on/off automatically. [CHAR LIMIT=30] -->
|
||||
<string name="dark_ui_auto_mode_never">None</string>
|
||||
<!-- Dark UIscreen, setting option value for Dark UI to turn on/off automatically at sunset/sunrise. [CHAR LIMIT=32] -->
|
||||
<string name="dark_ui_auto_mode_auto">Turns on from sunset to sunrise</string>
|
||||
<!-- Dark UIscreen, setting option name controlling the current activation status. [CHAR LIMIT=30] -->
|
||||
<string name="dark_ui_status_title">Status</string>
|
||||
<!-- Display settings screen, summary format of Dark UI when off. [CHAR LIMIT=NONE] -->
|
||||
<string name="dark_ui_summary_off">Off / <xliff:g name="auto_mode_summary" example="Never turn on automatically">%1$s</xliff:g></string>
|
||||
<!-- Display settings screen, summary of Dark UI when off and will *never* turn on automatically. [CHAR LIMIT=NONE] -->
|
||||
<string name="dark_ui_summary_off_auto_mode_never">Will never turn on automatically</string>
|
||||
<!-- Display settings screen, summary of Dark UI when off and will turn on automatically at sunset. [CHAR LIMIT=NONE] -->
|
||||
<string name="dark_ui_summary_off_auto_mode_auto">Will turn on automatically at sunset</string>
|
||||
<!-- Display settings screen, summary format of Dark UI when on. [CHAR LIMIT=NONE] -->
|
||||
<string name="dark_ui_summary_on">On / <xliff:g name="auto_mode_summary" example="Never turn off automatically">%1$s</xliff:g></string>
|
||||
<!-- Display settings screen, summary of Dark UI when on and will *never* turn off automatically. [CHAR LIMIT=NONE] -->
|
||||
<string name="dark_ui_summary_on_auto_mode_never">Will never turn off automatically</string>
|
||||
<!-- Display settings screen, summary of Dark UI when on and will turn off automatically at sunrise. [CHAR LIMIT=NONE] -->
|
||||
<string name="dark_ui_summary_on_auto_mode_auto">Will turn off automatically at sunrise</string>
|
||||
<!-- Dark theme screen, description of Dark theme feature. [CHAR LIMIT=NONE] -->
|
||||
<string name="dark_ui_text">Dark theme uses a black background to help keep battery alive longer on some screens. Dark theme schedules wait to turn on until your screen is off.</string>
|
||||
|
||||
<!-- Sound & display settings screen, setting option name to change screen timeout -->
|
||||
<string name="screen_timeout">Screen timeout</string>
|
||||
<!-- Sound & display settings screen, setting option name to change screen timeout [CHAR LIMIT=30] -->
|
||||
@@ -6880,6 +6916,7 @@
|
||||
<string name="help_url_connected_devices" translatable="false"></string>
|
||||
<string name="help_url_apps_and_notifications" translatable="false"></string>
|
||||
<string name="help_url_night_display" translatable="false"></string>
|
||||
<string name="help_url_dark_theme" translatable="false"></string>
|
||||
<string name="help_url_screen_saver" translatable="false"></string>
|
||||
<string name="help_url_pickup_gesture" translatable="false"></string>
|
||||
<string name="help_url_storage_dashboard" translatable="false"></string>
|
||||
@@ -9975,6 +10012,12 @@
|
||||
<!-- [CHAR_LIMIT=40] Positive button text in dark theme notification -->
|
||||
<string name="dark_ui_settings_dialog_acknowledge">Got it</string>
|
||||
|
||||
<!-- [CHAR_LIMIT=50] Title string in the dark theme slice(suggestion) -->
|
||||
<string name="dark_theme_slice_title">Try Dark theme</string>
|
||||
|
||||
<!-- [CHAR_LIMIT=50] Subtitle string in the dark theme slice(suggestion) -->
|
||||
<string name="dark_theme_slice_subtitle">Helps extend battery life</string>
|
||||
|
||||
<!-- [CHAR LIMIT=60] Name of dev option to enable extra quick settings tiles -->
|
||||
<string name="quick_settings_developer_tiles">Quick settings developer tiles</string>
|
||||
|
||||
@@ -11237,5 +11280,13 @@
|
||||
<string name="work_policy_privacy_settings">Your work policy info</string>
|
||||
<!-- Summary for Enterprise Privacy settings, explaining what the user can expect to find under it [CHAR LIMIT=NONE]-->
|
||||
<string name="work_policy_privacy_settings_summary">Settings managed by your IT admin</string>
|
||||
<!-- Title for RTT setting. [CHAR LIMIT=NONE] -->
|
||||
<string name="rtt_settings_title"></string>
|
||||
<!-- Subtext for showing the option of RTT setting. [CHAR LIMIT=NONE] -->
|
||||
<string name="rtt_settings_no_visible"></string>
|
||||
<!-- Subtext for showing the option of RTT setting. [CHAR LIMIT=NONE] -->
|
||||
<string name="rtt_settings_visible_during_call"></string>
|
||||
<!-- Subtext for showing the option of RTT setting. [CHAR LIMIT=NONE] -->
|
||||
<string name="rtt_settings_always_visible"></string>
|
||||
|
||||
</resources>
|
||||
|
49
res/xml/dark_mode_settings.xml
Normal file
49
res/xml/dark_mode_settings.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2019 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:title="@string/dark_ui_mode"
|
||||
android:key="dark_ui_mode_screen"
|
||||
settings:keywords="@string/keywords_dark_ui_mode">
|
||||
|
||||
<DropDownPreference
|
||||
android:key="dark_ui_auto_mode"
|
||||
android:title="@string/dark_ui_auto_mode_title"
|
||||
android:summary="%s"
|
||||
android:entries="@array/dark_ui_scheduler_preference_titles"
|
||||
android:entryValues="@array/dark_ui_scheduler_preference_titles"
|
||||
settings:controller="com.android.settings.display.darkmode.DarkModeScheduleSelectorController"
|
||||
settings:keywords="@string/keywords_dark_ui_mode"/>
|
||||
|
||||
<com.android.settingslib.widget.LayoutPreference
|
||||
android:key="dark_ui_activated"
|
||||
android:title="@string/dark_ui_title"
|
||||
android:selectable="false"
|
||||
android:layout="@layout/dark_ui_activation_button"
|
||||
settings:allowDividerBelow="true"
|
||||
settings:controller="com.android.settings.display.darkmode.DarkModeActivationPreferenceController"
|
||||
settings:keywords="@string/keywords_dark_ui_mode"/>
|
||||
|
||||
<com.android.settingslib.widget.FooterPreference
|
||||
android:key="dark_ui_footer"
|
||||
android:title="@string/dark_ui_text"
|
||||
android:selectable="false"
|
||||
settings:searchable="false"
|
||||
settings:allowDividerAbove="true"/>
|
||||
|
||||
</PreferenceScreen>
|
@@ -31,6 +31,15 @@
|
||||
<intent android:action="com.android.intent.action.SHOW_BRIGHTNESS_DIALOG" />
|
||||
</com.android.settingslib.RestrictedPreference>
|
||||
|
||||
<com.android.settings.display.darkmode.DarkModePreference
|
||||
android:key="dark_ui_mode"
|
||||
android:title="@string/dark_ui_mode"
|
||||
android:fragment="com.android.settings.display.darkmode.DarkModeSettingsFragment"
|
||||
android:widgetLayout="@null"
|
||||
settings:widgetLayout="@null"
|
||||
settings:controller="com.android.settings.display.DarkUIPreferenceController"
|
||||
settings:searchable="false"/>
|
||||
|
||||
<com.android.settings.display.NightDisplayPreference
|
||||
android:key="night_display"
|
||||
android:title="@string/night_display_title"
|
||||
@@ -54,13 +63,6 @@
|
||||
settings:controller="com.android.settings.display.WallpaperPreferenceController">
|
||||
</com.android.settingslib.RestrictedPreference>
|
||||
|
||||
|
||||
<SwitchPreference
|
||||
android:key="dark_ui_mode"
|
||||
android:title="@string/dark_ui_mode"
|
||||
settings:keywords="@string/keywords_dark_ui_mode"
|
||||
settings:controller="com.android.settings.display.DarkUIPreferenceController"/>
|
||||
|
||||
<!-- Cross-listed item, if you change this, also change it in power_usage_summary.xml -->
|
||||
<com.android.settings.display.TimeoutListPreference
|
||||
android:key="screen_timeout"
|
||||
|
@@ -22,13 +22,6 @@
|
||||
android:title="@string/privacy_dashboard_title"
|
||||
settings:initialExpandedChildrenCount="4">
|
||||
|
||||
<!-- This preference isn't searchable, and user won't see title in this preference.
|
||||
So, we just set empty text for title. -->
|
||||
<com.android.settingslib.widget.BarChartPreference
|
||||
android:key="permission_bar_chart"
|
||||
android:title="@string/summary_placeholder"
|
||||
settings:controller="com.android.settings.privacy.PermissionBarChartPreferenceController"/>
|
||||
|
||||
<!-- Work Policy info -->
|
||||
<Preference
|
||||
android:key="work_policy_info"
|
||||
|
@@ -51,13 +51,24 @@
|
||||
<PreferenceCategory
|
||||
android:key="security_settings_face_manage_category"
|
||||
android:title="@string/security_settings_face_settings_require_category">
|
||||
<SwitchPreference
|
||||
android:key="security_settings_face_require_attention"
|
||||
android:title="@string/security_settings_face_settings_require_attention"
|
||||
android:summary="@string/security_settings_face_settings_require_attention_details"
|
||||
app:keywords="@string/keywords_face_unlock"
|
||||
app:controller="com.android.settings.biometrics.face.FaceSettingsAttentionPreferenceController"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="security_settings_face_require_confirmation"
|
||||
android:title="@string/security_settings_face_settings_require_confirmation"
|
||||
android:summary="@string/security_settings_face_settings_require_confirmation_details"
|
||||
app:keywords="@string/keywords_face_unlock"
|
||||
app:controller="com.android.settings.biometrics.face.FaceSettingsConfirmPreferenceController"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="security_settings_face_button_category"
|
||||
android:title="@string/security_settings_face_preference_title">
|
||||
<com.android.settingslib.widget.LayoutPreference
|
||||
android:key="security_settings_face_delete_faces_container"
|
||||
android:selectable="false"
|
||||
@@ -66,7 +77,7 @@
|
||||
<com.android.settingslib.widget.LayoutPreference
|
||||
android:key="security_settings_face_enroll_faces_container"
|
||||
android:selectable="false"
|
||||
android:layout="@layout/face_enroll_button " />
|
||||
android:layout="@layout/face_enroll_button" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
|
@@ -24,7 +24,6 @@ import android.provider.SearchIndexableResource;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.display.BrightnessLevelPreferenceController;
|
||||
import com.android.settings.display.CameraGesturePreferenceController;
|
||||
import com.android.settings.display.DarkUIPreferenceController;
|
||||
import com.android.settings.display.LiftToWakePreferenceController;
|
||||
import com.android.settings.display.NightDisplayPreferenceController;
|
||||
import com.android.settings.display.NightModePreferenceController;
|
||||
@@ -67,7 +66,6 @@ public class DisplaySettings extends DashboardFragment {
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
use(DarkUIPreferenceController.class).setParentFragment(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -52,6 +52,7 @@ public class Settings extends SettingsActivity {
|
||||
public static class LocalePickerActivity extends SettingsActivity { /* empty */ }
|
||||
public static class LanguageAndInputSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class UserDictionarySettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class DarkThemeSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class DisplaySettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class NightDisplaySettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class NightDisplaySuggestionActivity extends NightDisplaySettingsActivity { /* empty */ }
|
||||
|
@@ -26,6 +26,7 @@ import android.widget.TextView;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.biometrics.BiometricEnrollIntroduction;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
|
||||
@@ -40,12 +41,15 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
private static final String TAG = "FaceIntro";
|
||||
|
||||
private FaceManager mFaceManager;
|
||||
private FaceFeatureProvider mFaceFeatureProvider;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mFaceManager = Utils.getFaceManagerOrNull(this);
|
||||
mFaceFeatureProvider = FeatureFactory.getFactory(getApplicationContext())
|
||||
.getFaceFeatureProvider();
|
||||
|
||||
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
|
||||
if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
|
||||
@@ -87,6 +91,12 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
});
|
||||
}
|
||||
|
||||
final TextView footer2 = findViewById(R.id.face_enroll_introduction_footer_part_2);
|
||||
final int footer2TextResource =
|
||||
mFaceFeatureProvider.isAttentionSupported(getApplicationContext())
|
||||
? R.string.security_settings_face_enroll_introduction_footer_part_2
|
||||
: R.string.security_settings_face_settings_footer_attention_not_supported;
|
||||
footer2.setText(footer2TextResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.face;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/** Feature provider for face unlock */
|
||||
public interface FaceFeatureProvider {
|
||||
/** Returns true if attention checking is supported. */
|
||||
boolean isAttentionSupported(Context context);
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.face;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
public class FaceFeatureProviderImpl implements FaceFeatureProvider {
|
||||
|
||||
@Override
|
||||
public boolean isAttentionSupported(Context context) {
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -37,6 +37,7 @@ import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
@@ -60,13 +61,16 @@ public class FaceSettings extends DashboardFragment {
|
||||
private FaceManager mFaceManager;
|
||||
private int mUserId;
|
||||
private byte[] mToken;
|
||||
private FaceSettingsAttentionPreferenceController mAttentionController;
|
||||
private FaceSettingsRemoveButtonPreferenceController mRemoveController;
|
||||
private FaceSettingsEnrollButtonPreferenceController mEnrollController;
|
||||
private FaceSettingsLockscreenBypassPreferenceController mLockscreenController;
|
||||
private List<AbstractPreferenceController> mControllers;
|
||||
|
||||
private List<Preference> mTogglePreferences;
|
||||
private Preference mRemoveButton;
|
||||
private Preference mEnrollButton;
|
||||
private FaceFeatureProvider mFaceFeatureProvider;
|
||||
|
||||
private boolean mConfirmingPassword;
|
||||
|
||||
@@ -117,6 +121,7 @@ public class FaceSettings extends DashboardFragment {
|
||||
mFaceManager = getPrefContext().getSystemService(FaceManager.class);
|
||||
mUserId = getActivity().getIntent().getIntExtra(
|
||||
Intent.EXTRA_USER_ID, UserHandle.myUserId());
|
||||
mFaceFeatureProvider = FeatureFactory.getFactory(getContext()).getFaceFeatureProvider();
|
||||
|
||||
if (mUserManager.getUserInfo(mUserId).isManagedProfile()) {
|
||||
getActivity().setTitle(getActivity().getResources().getString(
|
||||
@@ -125,11 +130,12 @@ public class FaceSettings extends DashboardFragment {
|
||||
|
||||
Preference keyguardPref = findPreference(FaceSettingsKeyguardPreferenceController.KEY);
|
||||
Preference appPref = findPreference(FaceSettingsAppPreferenceController.KEY);
|
||||
Preference attentionPref = findPreference(FaceSettingsAttentionPreferenceController.KEY);
|
||||
Preference confirmPref = findPreference(FaceSettingsConfirmPreferenceController.KEY);
|
||||
Preference bypassPref =
|
||||
findPreference(FaceSettingsLockscreenBypassPreferenceController.KEY);
|
||||
findPreference(mLockscreenController.getPreferenceKey());
|
||||
mTogglePreferences = new ArrayList<>(
|
||||
Arrays.asList(keyguardPref, appPref, confirmPref, bypassPref));
|
||||
Arrays.asList(keyguardPref, appPref, attentionPref, confirmPref, bypassPref));
|
||||
|
||||
mRemoveButton = findPreference(FaceSettingsRemoveButtonPreferenceController.KEY);
|
||||
mEnrollButton = findPreference(FaceSettingsEnrollButtonPreferenceController.KEY);
|
||||
@@ -147,6 +153,7 @@ public class FaceSettings extends DashboardFragment {
|
||||
// Don't show keyguard controller for work profile settings.
|
||||
if (mUserManager.isManagedProfile(mUserId)) {
|
||||
removePreference(FaceSettingsKeyguardPreferenceController.KEY);
|
||||
removePreference(mLockscreenController.getPreferenceKey());
|
||||
}
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
@@ -154,6 +161,14 @@ public class FaceSettings extends DashboardFragment {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
|
||||
mLockscreenController = use(FaceSettingsLockscreenBypassPreferenceController.class);
|
||||
mLockscreenController.setUserId(mUserId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
@@ -173,12 +188,17 @@ public class FaceSettings extends DashboardFragment {
|
||||
finish();
|
||||
}
|
||||
} else {
|
||||
mAttentionController.setToken(mToken);
|
||||
mEnrollController.setToken(mToken);
|
||||
}
|
||||
|
||||
final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId);
|
||||
mEnrollButton.setVisible(!hasEnrolled);
|
||||
mRemoveButton.setVisible(hasEnrolled);
|
||||
|
||||
if (!mFaceFeatureProvider.isAttentionSupported(getContext())) {
|
||||
removePreference(FaceSettingsAttentionPreferenceController.KEY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -193,6 +213,7 @@ public class FaceSettings extends DashboardFragment {
|
||||
mToken = data.getByteArrayExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
|
||||
if (mToken != null) {
|
||||
mAttentionController.setToken(mToken);
|
||||
mEnrollController.setToken(mToken);
|
||||
}
|
||||
}
|
||||
@@ -236,7 +257,9 @@ public class FaceSettings extends DashboardFragment {
|
||||
mControllers = buildPreferenceControllers(context, getSettingsLifecycle());
|
||||
// There's no great way of doing this right now :/
|
||||
for (AbstractPreferenceController controller : mControllers) {
|
||||
if (controller instanceof FaceSettingsRemoveButtonPreferenceController) {
|
||||
if (controller instanceof FaceSettingsAttentionPreferenceController) {
|
||||
mAttentionController = (FaceSettingsAttentionPreferenceController) controller;
|
||||
} else if (controller instanceof FaceSettingsRemoveButtonPreferenceController) {
|
||||
mRemoveController = (FaceSettingsRemoveButtonPreferenceController) controller;
|
||||
mRemoveController.setListener(mRemovalListener);
|
||||
mRemoveController.setActivity((SettingsActivity) getActivity());
|
||||
@@ -255,6 +278,7 @@ public class FaceSettings extends DashboardFragment {
|
||||
controllers.add(new FaceSettingsVideoPreferenceController(context));
|
||||
controllers.add(new FaceSettingsKeyguardPreferenceController(context));
|
||||
controllers.add(new FaceSettingsAppPreferenceController(context));
|
||||
controllers.add(new FaceSettingsAttentionPreferenceController(context));
|
||||
controllers.add(new FaceSettingsRemoveButtonPreferenceController(context));
|
||||
controllers.add(new FaceSettingsFooterPreferenceController(context));
|
||||
controllers.add(new FaceSettingsConfirmPreferenceController(context));
|
||||
|
@@ -23,6 +23,7 @@ import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.utils.AnnotationSpan;
|
||||
import com.android.settingslib.HelpUtils;
|
||||
import com.android.settingslib.widget.FooterPreference;
|
||||
@@ -34,8 +35,11 @@ public class FaceSettingsFooterPreferenceController extends BasePreferenceContro
|
||||
|
||||
private static final String ANNOTATION_URL = "url";
|
||||
|
||||
private FaceFeatureProvider mProvider;
|
||||
|
||||
public FaceSettingsFooterPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mProvider = FeatureFactory.getFactory(context).getFaceFeatureProvider();
|
||||
}
|
||||
|
||||
public FaceSettingsFooterPreferenceController(Context context) {
|
||||
@@ -55,7 +59,12 @@ public class FaceSettingsFooterPreferenceController extends BasePreferenceContro
|
||||
mContext, mContext.getString(R.string.help_url_face), getClass().getName());
|
||||
final AnnotationSpan.LinkInfo linkInfo =
|
||||
new AnnotationSpan.LinkInfo(mContext, ANNOTATION_URL, helpIntent);
|
||||
|
||||
final int footerRes = mProvider.isAttentionSupported(mContext)
|
||||
? R.string.security_settings_face_settings_footer
|
||||
: R.string.security_settings_face_settings_footer_attention_not_supported;
|
||||
|
||||
preference.setTitle(AnnotationSpan.linkify(
|
||||
mContext.getText(R.string.security_settings_face_settings_footer), linkInfo));
|
||||
mContext.getText(footerRes), linkInfo));
|
||||
}
|
||||
}
|
||||
|
@@ -30,8 +30,6 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
public class FaceSettingsLockscreenBypassPreferenceController
|
||||
extends FaceSettingsPreferenceController {
|
||||
|
||||
static final String KEY = "security_lockscreen_bypass";
|
||||
|
||||
@VisibleForTesting
|
||||
protected FaceManager mFaceManager;
|
||||
private UserManager mUserManager;
|
||||
|
@@ -60,6 +60,7 @@ import java.util.Map;
|
||||
public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceController implements
|
||||
LifecycleObserver, OnStart, OnStop, OnDestroy, CachedBluetoothDevice.Callback {
|
||||
private static final String TAG = "AdvancedBtHeaderCtrl";
|
||||
private static final int LOW_BATTERY_LEVEL = 20;
|
||||
|
||||
@VisibleForTesting
|
||||
LayoutPreference mLayoutPreference;
|
||||
@@ -180,12 +181,18 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
||||
Drawable createBtBatteryIcon(Context context, int level, boolean charging) {
|
||||
final BatteryMeterView.BatteryMeterDrawable drawable =
|
||||
new BatteryMeterView.BatteryMeterDrawable(context,
|
||||
context.getColor(R.color.meter_background_color));
|
||||
context.getColor(R.color.meter_background_color),
|
||||
context.getResources().getDimensionPixelSize(
|
||||
R.dimen.advanced_bluetooth_battery_meter_width),
|
||||
context.getResources().getDimensionPixelSize(
|
||||
R.dimen.advanced_bluetooth_battery_meter_height));
|
||||
drawable.setBatteryLevel(level);
|
||||
final int attr = level > LOW_BATTERY_LEVEL || charging
|
||||
? android.R.attr.colorControlNormal
|
||||
: android.R.attr.colorError;
|
||||
drawable.setColorFilter(new PorterDuffColorFilter(
|
||||
com.android.settings.Utils.getColorAttrDefaultColor(context,
|
||||
android.R.attr.colorControlNormal),
|
||||
PorterDuff.Mode.SRC_IN));
|
||||
com.android.settings.Utils.getColorAttrDefaultColor(context, attr),
|
||||
PorterDuff.Mode.SRC));
|
||||
drawable.setCharging(charging);
|
||||
|
||||
return drawable;
|
||||
|
@@ -136,6 +136,6 @@ public class BluetoothSliceBuilder {
|
||||
final Intent intent = new Intent(ACTION_BLUETOOTH_SLICE_CHANGED)
|
||||
.setClass(context, SliceBroadcastReceiver.class);
|
||||
return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ package com.android.settings.core;
|
||||
|
||||
import android.annotation.LayoutRes;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -26,6 +27,7 @@ import android.content.pm.PackageManager;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -61,6 +63,10 @@ public class SettingsBaseActivity extends FragmentActivity {
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (isLockTaskModePinned() && !isSettingsRunOnTop()) {
|
||||
Log.w(TAG, "Devices lock task mode pinned.");
|
||||
finish();
|
||||
}
|
||||
final long startTime = System.currentTimeMillis();
|
||||
getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
|
||||
|
||||
@@ -148,6 +154,20 @@ public class SettingsBaseActivity extends FragmentActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLockTaskModePinned() {
|
||||
final ActivityManager activityManager =
|
||||
getApplicationContext().getSystemService(ActivityManager.class);
|
||||
return activityManager.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_PINNED;
|
||||
}
|
||||
|
||||
private boolean isSettingsRunOnTop() {
|
||||
final ActivityManager activityManager =
|
||||
getApplicationContext().getSystemService(ActivityManager.class);
|
||||
final String taskPkgName = activityManager.getRunningTasks(1 /* maxNum */)
|
||||
.get(0 /* index */).baseActivity.getPackageName();
|
||||
return TextUtils.equals(getPackageName(), taskPkgName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether or not the enabled state actually changed.
|
||||
*/
|
||||
|
@@ -74,6 +74,7 @@ import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment;
|
||||
import com.android.settings.deviceinfo.firmwareversion.FirmwareVersionSettings;
|
||||
import com.android.settings.deviceinfo.legal.ModuleLicensesDashboard;
|
||||
import com.android.settings.display.NightDisplaySettings;
|
||||
import com.android.settings.display.darkmode.DarkModeSettingsFragment;
|
||||
import com.android.settings.dream.DreamSettings;
|
||||
import com.android.settings.enterprise.EnterprisePrivacySettings;
|
||||
import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
|
||||
@@ -281,7 +282,8 @@ public class SettingsGateway {
|
||||
PreviouslyConnectedDeviceDashboardFragment.class.getName(),
|
||||
BatterySaverScheduleSettings.class.getName(),
|
||||
MobileNetworkListFragment.class.getName(),
|
||||
GlobalActionsPanelSettings.class.getName()
|
||||
GlobalActionsPanelSettings.class.getName(),
|
||||
DarkModeSettingsFragment.class.getName()
|
||||
};
|
||||
|
||||
public static final String[] SETTINGS_FOR_RESTRICTED = {
|
||||
|
@@ -111,7 +111,7 @@ public class MainlineModuleVersionPreferenceController extends BasePreferenceCon
|
||||
try {
|
||||
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern,
|
||||
Locale.getDefault());
|
||||
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
simpleDateFormat.setTimeZone(TimeZone.getDefault());
|
||||
return Optional.of(simpleDateFormat.parse(text));
|
||||
} catch (ParseException e) {
|
||||
// ignore and try next pattern
|
||||
|
@@ -21,6 +21,7 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
|
||||
@@ -28,7 +29,6 @@ import androidx.annotation.VisibleForTesting;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
@@ -44,7 +44,7 @@ public class DarkUIPreferenceController extends TogglePreferenceController imple
|
||||
public static final int DIALOG_SEEN = 1;
|
||||
|
||||
@VisibleForTesting
|
||||
SwitchPreference mPreference;
|
||||
Preference mPreference;
|
||||
|
||||
private UiModeManager mUiModeManager;
|
||||
private PowerManager mPowerManager;
|
||||
@@ -68,7 +68,8 @@ public class DarkUIPreferenceController extends TogglePreferenceController imple
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES;
|
||||
return (mContext.getResources().getConfiguration().uiMode
|
||||
& Configuration.UI_MODE_NIGHT_YES) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -90,17 +91,13 @@ public class DarkUIPreferenceController extends TogglePreferenceController imple
|
||||
Settings.Secure.DARK_MODE_DIALOG_SEEN, 0) == DIALOG_SEEN;
|
||||
if (!dialogSeen && isChecked) {
|
||||
showDarkModeDialog();
|
||||
return false;
|
||||
}
|
||||
mUiModeManager.setNightMode(isChecked
|
||||
? UiModeManager.MODE_NIGHT_YES
|
||||
: UiModeManager.MODE_NIGHT_NO);
|
||||
return true;
|
||||
return mUiModeManager.setNightModeActivated(isChecked);
|
||||
}
|
||||
|
||||
private void showDarkModeDialog() {
|
||||
final DarkUIInfoDialogFragment frag = new DarkUIInfoDialogFragment();
|
||||
if (mFragment.getFragmentManager() != null) {
|
||||
if (mFragment != null && mFragment.getFragmentManager() != null) {
|
||||
frag.show(mFragment.getFragmentManager(), getClass().getName());
|
||||
}
|
||||
}
|
||||
@@ -113,12 +110,10 @@ public class DarkUIPreferenceController extends TogglePreferenceController imple
|
||||
boolean isBatterySaver = isPowerSaveMode();
|
||||
mPreference.setEnabled(!isBatterySaver);
|
||||
if (isBatterySaver) {
|
||||
int stringId = mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES
|
||||
int stringId = isChecked()
|
||||
? R.string.dark_ui_mode_disabled_summary_dark_theme_on
|
||||
: R.string.dark_ui_mode_disabled_summary_dark_theme_off;
|
||||
mPreference.setSummary(mContext.getString(stringId));
|
||||
} else {
|
||||
mPreference.setSummary(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,22 +122,17 @@ public class DarkUIPreferenceController extends TogglePreferenceController imple
|
||||
return mPowerManager.isPowerSaveMode();
|
||||
}
|
||||
|
||||
|
||||
@VisibleForTesting
|
||||
void setUiModeManager(UiModeManager uiModeManager) {
|
||||
mUiModeManager = uiModeManager;
|
||||
}
|
||||
|
||||
public void setParentFragment(Fragment fragment) {
|
||||
mFragment = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
mContext.registerReceiver(mReceiver,
|
||||
new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
|
||||
}
|
||||
|
||||
// used by AccessibilitySettings
|
||||
public void setParentFragment(Fragment fragment) {
|
||||
mFragment = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
mContext.unregisterReceiver(mReceiver);
|
||||
|
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.display.darkmode;
|
||||
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.PowerManager;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.widget.LayoutPreference;
|
||||
|
||||
/**
|
||||
* Controller for activate/deactivate night mode button
|
||||
*/
|
||||
public class DarkModeActivationPreferenceController extends BasePreferenceController {
|
||||
private final UiModeManager mUiModeManager;
|
||||
private PowerManager mPowerManager;
|
||||
private Button mTurnOffButton;
|
||||
private Button mTurnOnButton;
|
||||
|
||||
public DarkModeActivationPreferenceController(Context context,
|
||||
String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mPowerManager = context.getSystemService(PowerManager.class);
|
||||
mUiModeManager = context.getSystemService(UiModeManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void updateState(Preference preference) {
|
||||
|
||||
final boolean batterySaver = mPowerManager.isPowerSaveMode();
|
||||
if (batterySaver) {
|
||||
mTurnOnButton.setVisibility(View.GONE);
|
||||
mTurnOffButton.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean active = (mContext.getResources().getConfiguration().uiMode
|
||||
& Configuration.UI_MODE_NIGHT_YES) != 0;
|
||||
updateNightMode(active);
|
||||
}
|
||||
|
||||
private void updateNightMode(boolean active) {
|
||||
final int autoMode = mUiModeManager.getNightMode();
|
||||
String buttonText;
|
||||
|
||||
if (autoMode == UiModeManager.MODE_NIGHT_AUTO) {
|
||||
buttonText = mContext.getString(active
|
||||
? R.string.dark_ui_activation_off_auto
|
||||
: R.string.dark_ui_activation_on_auto);
|
||||
} else {
|
||||
buttonText = mContext.getString(active
|
||||
? R.string.dark_ui_activation_off_manual
|
||||
: R.string.dark_ui_activation_on_manual);
|
||||
}
|
||||
if (active) {
|
||||
mTurnOnButton.setVisibility(View.GONE);
|
||||
mTurnOffButton.setVisibility(View.VISIBLE);
|
||||
mTurnOffButton.setText(buttonText);
|
||||
} else {
|
||||
mTurnOnButton.setVisibility(View.VISIBLE);
|
||||
mTurnOffButton.setVisibility(View.GONE);
|
||||
mTurnOnButton.setText(buttonText);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
final boolean isActivated = (mContext.getResources().getConfiguration().uiMode
|
||||
& Configuration.UI_MODE_NIGHT_YES) != 0;
|
||||
final int autoMode = mUiModeManager.getNightMode();
|
||||
if (autoMode == UiModeManager.MODE_NIGHT_AUTO) {
|
||||
return mContext.getString(isActivated
|
||||
? R.string.dark_ui_summary_on_auto_mode_auto
|
||||
: R.string.dark_ui_summary_off_auto_mode_auto);
|
||||
} else {
|
||||
return mContext.getString(isActivated
|
||||
? R.string.dark_ui_summary_on_auto_mode_never
|
||||
: R.string.dark_ui_summary_off_auto_mode_never);
|
||||
}
|
||||
}
|
||||
|
||||
private final View.OnClickListener mListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final boolean active = (mContext.getResources().getConfiguration().uiMode
|
||||
& Configuration.UI_MODE_NIGHT_YES) != 0;
|
||||
mUiModeManager.setNightModeActivated(!active);
|
||||
updateNightMode(!active);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
|
||||
final LayoutPreference preference = screen.findPreference(getPreferenceKey());
|
||||
mTurnOnButton = preference.findViewById(R.id.dark_ui_turn_on_button);
|
||||
mTurnOnButton.setOnClickListener(mListener);
|
||||
mTurnOffButton = preference.findViewById(R.id.dark_ui_turn_off_button);
|
||||
mTurnOffButton.setOnClickListener(mListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
}
|
103
src/com/android/settings/display/darkmode/DarkModeObserver.java
Normal file
103
src/com/android/settings/display/darkmode/DarkModeObserver.java
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.display.darkmode;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Observes changes for dark night settings*/
|
||||
public class DarkModeObserver {
|
||||
private static final String TAG = "DarkModeObserver";
|
||||
private ContentObserver mContentObserver;
|
||||
private final BroadcastReceiver mBatterySaverReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
mCallback.run();
|
||||
}
|
||||
};
|
||||
private Runnable mCallback;
|
||||
private Context mContext;
|
||||
|
||||
public DarkModeObserver(Context context) {
|
||||
mContext = context;
|
||||
mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
super.onChange(selfChange, uri);
|
||||
final String setting = uri == null ? null : uri.getLastPathSegment();
|
||||
if (setting != null && mCallback != null) {
|
||||
switch (setting) {
|
||||
case Settings.Secure.UI_NIGHT_MODE:
|
||||
mCallback.run();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* subscribe callback when night mode changed in the database
|
||||
*
|
||||
* @param callback the callback that gets triggered when subscribed
|
||||
*/
|
||||
public void subscribe(Runnable callback) {
|
||||
callback.run();
|
||||
mCallback = callback;
|
||||
final Uri uri = Settings.Secure.getUriFor(Settings.Secure.UI_NIGHT_MODE);
|
||||
mContext.getContentResolver().registerContentObserver(uri, false, mContentObserver);
|
||||
final IntentFilter batteryFilter = new IntentFilter();
|
||||
batteryFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
|
||||
mContext.registerReceiver(
|
||||
mBatterySaverReceiver, batteryFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* unsubscribe from dark ui database changes
|
||||
*/
|
||||
public void unsubscribe() {
|
||||
mContext.getContentResolver().unregisterContentObserver(mContentObserver);
|
||||
try {
|
||||
mContext.unregisterReceiver(mBatterySaverReceiver);
|
||||
} catch (IllegalArgumentException e) {
|
||||
/* Ignore: unregistering an unregistered receiver */
|
||||
Log.w(TAG, e.getMessage());
|
||||
}
|
||||
// NO-OP
|
||||
mCallback = null;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void setContentObserver(ContentObserver co) {
|
||||
mContentObserver = co;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected ContentObserver getContentObserver() {
|
||||
return mContentObserver;
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.display.darkmode;
|
||||
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.PowerManager;
|
||||
import android.util.AttributeSet;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.widget.MasterSwitchPreference;
|
||||
|
||||
/**
|
||||
* component for the display settings dark ui summary*/
|
||||
public class DarkModePreference extends MasterSwitchPreference {
|
||||
|
||||
private UiModeManager mUiModeManager;
|
||||
private DarkModeObserver mDarkModeObserver;
|
||||
private PowerManager mPowerManager;
|
||||
private Runnable mCallback;
|
||||
|
||||
public DarkModePreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mDarkModeObserver = new DarkModeObserver(context);
|
||||
mUiModeManager = context.getSystemService(UiModeManager.class);
|
||||
mPowerManager = context.getSystemService(PowerManager.class);
|
||||
mCallback = () -> {
|
||||
final boolean batterySaver = mPowerManager.isPowerSaveMode();
|
||||
final boolean active = (getContext().getResources().getConfiguration().uiMode
|
||||
& Configuration.UI_MODE_NIGHT_YES) != 0;
|
||||
setSwitchEnabled(!batterySaver);
|
||||
updateSummary(batterySaver, active);
|
||||
};
|
||||
mDarkModeObserver.subscribe(mCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttached() {
|
||||
super.onAttached();
|
||||
mDarkModeObserver.subscribe(mCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetached() {
|
||||
super.onDetached();
|
||||
mDarkModeObserver.unsubscribe();
|
||||
}
|
||||
|
||||
private void updateSummary(boolean batterySaver, boolean active) {
|
||||
if (batterySaver) {
|
||||
final int stringId = active ? R.string.dark_ui_mode_disabled_summary_dark_theme_on
|
||||
: R.string.dark_ui_mode_disabled_summary_dark_theme_off;
|
||||
setSummary(getContext().getString(stringId));
|
||||
return;
|
||||
}
|
||||
final boolean auto = mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_AUTO;
|
||||
|
||||
String detail;
|
||||
if (active) {
|
||||
detail = getContext().getString(auto
|
||||
? R.string.dark_ui_summary_on_auto_mode_auto
|
||||
: R.string.dark_ui_summary_on_auto_mode_never);
|
||||
} else {
|
||||
detail = getContext().getString(auto
|
||||
? R.string.dark_ui_summary_off_auto_mode_auto
|
||||
: R.string.dark_ui_summary_off_auto_mode_never);
|
||||
}
|
||||
String summary = getContext().getString(active
|
||||
? R.string.dark_ui_summary_on
|
||||
: R.string.dark_ui_summary_off, detail);
|
||||
|
||||
setSummary(summary);
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.display.darkmode;
|
||||
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.PowerManager;
|
||||
import androidx.preference.DropDownPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/**
|
||||
* Controller for the dark ui option dropdown
|
||||
*/
|
||||
public class DarkModeScheduleSelectorController extends BasePreferenceController
|
||||
implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
private final UiModeManager mUiModeManager;
|
||||
private PowerManager mPowerManager;
|
||||
private DropDownPreference mPreference;
|
||||
private String mCurrentMode;
|
||||
|
||||
public DarkModeScheduleSelectorController(Context context, String key) {
|
||||
super(context, key);
|
||||
mUiModeManager = context.getSystemService(UiModeManager.class);
|
||||
mPowerManager = context.getSystemService(PowerManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
|
||||
mPreference = screen.findPreference(getPreferenceKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return BasePreferenceController.AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void updateState(Preference preference) {
|
||||
final boolean batterySaver = mPowerManager.isPowerSaveMode();
|
||||
mPreference.setEnabled(!batterySaver);
|
||||
mCurrentMode =
|
||||
mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_AUTO
|
||||
? mContext.getString(R.string.dark_ui_auto_mode_auto)
|
||||
: mContext.getString(R.string.dark_ui_auto_mode_never);
|
||||
mPreference.setValue(mCurrentMode);
|
||||
}
|
||||
@Override
|
||||
public final boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
String newMode = (String) newValue;
|
||||
if (newMode == mCurrentMode) {
|
||||
return false;
|
||||
}
|
||||
mCurrentMode = newMode;
|
||||
if (mCurrentMode == mContext.getString(R.string.dark_ui_auto_mode_never)) {
|
||||
boolean active = (mContext.getResources().getConfiguration().uiMode
|
||||
& Configuration.UI_MODE_NIGHT_YES) != 0;
|
||||
int mode = active ? UiModeManager.MODE_NIGHT_YES
|
||||
: UiModeManager.MODE_NIGHT_NO;
|
||||
mUiModeManager.setNightMode(mode);
|
||||
|
||||
} else if (mCurrentMode ==
|
||||
mContext.getString(R.string.dark_ui_auto_mode_auto)) {
|
||||
mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_AUTO);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.display.darkmode;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
/**
|
||||
* Settings screen for Dark UI Mode
|
||||
*/
|
||||
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
||||
public class DarkModeSettingsFragment extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "DarkModeSettingsFragment";
|
||||
private DarkModeObserver mContentObserver;
|
||||
private Runnable mCallback = () -> {
|
||||
updatePreferenceStates();
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final Context context = getContext();
|
||||
mContentObserver = new DarkModeObserver(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
// Listen for changes only while visible.
|
||||
mContentObserver.subscribe(mCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
// Stop listening for state changes.
|
||||
mContentObserver.unsubscribe();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.dark_mode_settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHelpResource() {
|
||||
return R.string.help_url_dark_theme;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.DARK_UI_SETTINGS;
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider();
|
||||
}
|
@@ -55,8 +55,6 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
|
||||
TextView mBatteryPercentText;
|
||||
@VisibleForTesting
|
||||
TextView mSummary1;
|
||||
@VisibleForTesting
|
||||
TextView mSummary2;
|
||||
|
||||
private Activity mActivity;
|
||||
private PreferenceFragmentCompat mHost;
|
||||
@@ -90,7 +88,6 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
|
||||
.findViewById(R.id.battery_header_icon);
|
||||
mBatteryPercentText = mBatteryLayoutPref.findViewById(R.id.battery_percent);
|
||||
mSummary1 = mBatteryLayoutPref.findViewById(R.id.summary1);
|
||||
mSummary2 = mBatteryLayoutPref.findViewById(R.id.summary2);
|
||||
|
||||
quickUpdateHeaderPreference();
|
||||
}
|
||||
@@ -115,9 +112,6 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
|
||||
} else {
|
||||
mSummary1.setText(info.remainingLabel);
|
||||
}
|
||||
// Clear this just to be sure we don't get UI jank on re-entering this view from another
|
||||
// activity.
|
||||
mSummary2.setText("");
|
||||
|
||||
mBatteryMeterView.setBatteryLevel(info.batteryLevel);
|
||||
mBatteryMeterView.setCharging(!info.discharging);
|
||||
|
@@ -117,6 +117,13 @@ public class BatteryMeterView extends ImageView {
|
||||
.getDimensionPixelSize(R.dimen.battery_meter_height);
|
||||
}
|
||||
|
||||
public BatteryMeterDrawable(Context context, int frameColor, int width, int height) {
|
||||
super(context, frameColor);
|
||||
|
||||
mIntrinsicWidth = width;
|
||||
mIntrinsicHeight = height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
return mIntrinsicWidth;
|
||||
|
@@ -19,7 +19,6 @@ package com.android.settings.fuelgauge;
|
||||
import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
@@ -27,7 +26,6 @@ import android.os.BatteryStats;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.Global;
|
||||
import android.text.format.Formatter;
|
||||
import android.view.Menu;
|
||||
@@ -162,7 +160,6 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
|
||||
final TextView percentRemaining =
|
||||
mBatteryLayoutPref.findViewById(R.id.battery_percent);
|
||||
final TextView summary1 = mBatteryLayoutPref.findViewById(R.id.summary1);
|
||||
final TextView summary2 = mBatteryLayoutPref.findViewById(R.id.summary2);
|
||||
BatteryInfo oldInfo = batteryInfos.get(0);
|
||||
BatteryInfo newInfo = batteryInfos.get(1);
|
||||
percentRemaining.setText(Utils.formatPercentage(oldInfo.batteryLevel));
|
||||
@@ -170,14 +167,13 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
|
||||
// set the text to the old estimate (copied from battery info). Note that this
|
||||
// can sometimes say 0 time remaining because battery stats requires the phone
|
||||
// be unplugged for a period of time before being willing ot make an estimate.
|
||||
summary1.setText(mPowerFeatureProvider.getOldEstimateDebugString(
|
||||
final String OldEstimateString = mPowerFeatureProvider.getOldEstimateDebugString(
|
||||
Formatter.formatShortElapsedTime(getContext(),
|
||||
PowerUtil.convertUsToMs(oldInfo.remainingTimeUs))));
|
||||
|
||||
// for this one we can just set the string directly
|
||||
summary2.setText(mPowerFeatureProvider.getEnhancedEstimateDebugString(
|
||||
PowerUtil.convertUsToMs(oldInfo.remainingTimeUs)));
|
||||
final String NewEstimateString = mPowerFeatureProvider.getEnhancedEstimateDebugString(
|
||||
Formatter.formatShortElapsedTime(getContext(),
|
||||
PowerUtil.convertUsToMs(newInfo.remainingTimeUs))));
|
||||
PowerUtil.convertUsToMs(newInfo.remainingTimeUs)));
|
||||
summary1.setText(OldEstimateString + "\n" + NewEstimateString);
|
||||
|
||||
batteryView.setBatteryLevel(oldInfo.batteryLevel);
|
||||
batteryView.setCharging(!oldInfo.discharging);
|
||||
|
@@ -33,6 +33,7 @@ import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accounts.AvatarViewMixin;
|
||||
import com.android.settings.core.HideNonSystemOverlayMixin;
|
||||
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
|
||||
@@ -54,8 +55,8 @@ public class SettingsHomepageActivity extends FragmentActivity {
|
||||
.initSearchToolbar(this /* activity */, toolbar, SettingsEnums.SETTINGS_HOMEPAGE);
|
||||
|
||||
final ImageView avatarView = findViewById(R.id.account_avatar);
|
||||
final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(this, avatarView);
|
||||
getLifecycle().addObserver(avatarViewMixin);
|
||||
getLifecycle().addObserver(new AvatarViewMixin(this, avatarView));
|
||||
getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
|
||||
|
||||
if (!getSystemService(ActivityManager.class).isLowRamDevice()) {
|
||||
// Only allow contextual feature on high ram devices.
|
||||
|
@@ -37,12 +37,11 @@ import com.android.settings.homepage.contextualcards.logging.ContextualCardLogUt
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
import com.android.settingslib.utils.AsyncLoaderCompat;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
@@ -56,7 +55,6 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
|
||||
private static final String TAG = "ContextualCardLoader";
|
||||
private static final long ELIGIBILITY_CHECKER_TIMEOUT_MS = 250;
|
||||
|
||||
private final ExecutorService mExecutorService;
|
||||
private final ContentObserver mObserver = new ContentObserver(
|
||||
new Handler(Looper.getMainLooper())) {
|
||||
@Override
|
||||
@@ -76,7 +74,6 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
|
||||
ContextualCardLoader(Context context) {
|
||||
super(context);
|
||||
mContext = context.getApplicationContext();
|
||||
mExecutorService = Executors.newCachedThreadPool();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -163,8 +160,8 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
|
||||
final List<Future<ContextualCard>> eligibleCards = new ArrayList<>();
|
||||
|
||||
for (ContextualCard card : candidates) {
|
||||
final EligibleCardChecker future = new EligibleCardChecker(mContext, card);
|
||||
eligibleCards.add(mExecutorService.submit(future));
|
||||
final EligibleCardChecker checker = new EligibleCardChecker(mContext, card);
|
||||
eligibleCards.add(ThreadUtils.postOnBackgroundThread(checker));
|
||||
}
|
||||
// Collect future and eligible cards
|
||||
for (Future<ContextualCard> cardFuture : eligibleCards) {
|
||||
|
@@ -78,6 +78,12 @@ public class SettingsContextualCardProvider extends ContextualCardProvider {
|
||||
.setCardName(CustomSliceRegistry.FACE_ENROLL_SLICE_URI.toString())
|
||||
.setCardCategory(ContextualCard.Category.DEFAULT)
|
||||
.build();
|
||||
final ContextualCard darkThemeCard =
|
||||
ContextualCard.newBuilder()
|
||||
.setSliceUri(CustomSliceRegistry.DARK_THEME_SLICE_URI.toString())
|
||||
.setCardName(CustomSliceRegistry.DARK_THEME_SLICE_URI.toString())
|
||||
.setCardCategory(ContextualCard.Category.IMPORTANT)
|
||||
.build();
|
||||
final ContextualCardList cards = ContextualCardList.newBuilder()
|
||||
.addCard(wifiCard)
|
||||
.addCard(connectedDeviceCard)
|
||||
@@ -86,6 +92,7 @@ public class SettingsContextualCardProvider extends ContextualCardProvider {
|
||||
.addCard(notificationChannelCard)
|
||||
.addCard(contextualAdaptiveSleepCard)
|
||||
.addCard(contextualFaceSettingsCard)
|
||||
.addCard(darkThemeCard)
|
||||
.build();
|
||||
|
||||
return cards;
|
||||
|
@@ -23,13 +23,12 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.homepage.contextualcards.ContextualCard;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
@@ -42,7 +41,6 @@ public class ConditionManager {
|
||||
|
||||
private static final long DISPLAYABLE_CHECKER_TIMEOUT_MS = 20;
|
||||
|
||||
private final ExecutorService mExecutorService;
|
||||
private final Context mAppContext;
|
||||
private final ConditionListener mListener;
|
||||
|
||||
@@ -50,7 +48,6 @@ public class ConditionManager {
|
||||
|
||||
public ConditionManager(Context context, ConditionListener listener) {
|
||||
mAppContext = context.getApplicationContext();
|
||||
mExecutorService = Executors.newCachedThreadPool();
|
||||
mCardControllers = new ArrayList<>();
|
||||
mListener = listener;
|
||||
initCandidates();
|
||||
@@ -64,8 +61,8 @@ public class ConditionManager {
|
||||
final List<Future<ContextualCard>> displayableCards = new ArrayList<>();
|
||||
// Check displayable future
|
||||
for (ConditionalCardController card : mCardControllers) {
|
||||
final DisplayableChecker future = new DisplayableChecker(getController(card.getId()));
|
||||
displayableCards.add(mExecutorService.submit(future));
|
||||
final DisplayableChecker checker = new DisplayableChecker(getController(card.getId()));
|
||||
displayableCards.add(ThreadUtils.postOnBackgroundThread(checker));
|
||||
}
|
||||
// Collect future and add displayable cards
|
||||
for (Future<ContextualCard> cardFuture : displayableCards) {
|
||||
|
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.homepage.contextualcards.slices;
|
||||
|
||||
import static androidx.slice.builders.ListBuilder.ICON_IMAGE;
|
||||
|
||||
import static android.provider.Settings.Global.LOW_POWER_MODE;
|
||||
|
||||
import android.annotation.ColorInt;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.builders.ListBuilder;
|
||||
import androidx.slice.builders.SliceAction;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.slices.CustomSliceRegistry;
|
||||
import com.android.settings.slices.CustomSliceable;
|
||||
import com.android.settings.slices.SliceBackgroundWorker;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class DarkThemeSlice implements CustomSliceable {
|
||||
private static final String TAG = "DarkThemeSlice";
|
||||
private static final int BATTERY_LEVEL_THRESHOLD = 50;
|
||||
private static final int DELAY_TIME_EXECUTING_DARK_THEME = 200;
|
||||
|
||||
// Keep the slice even Dark theme mode changed when it is on HomePage
|
||||
@VisibleForTesting
|
||||
static boolean sKeepSliceShow;
|
||||
@VisibleForTesting
|
||||
static long sActiveUiSession = -1000;
|
||||
|
||||
private final Context mContext;
|
||||
private final UiModeManager mUiModeManager;
|
||||
private final PowerManager mPowerManager;
|
||||
|
||||
public DarkThemeSlice(Context context) {
|
||||
mContext = context;
|
||||
mUiModeManager = context.getSystemService(UiModeManager.class);
|
||||
mPowerManager = context.getSystemService(PowerManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice getSlice() {
|
||||
final long currentUiSession = FeatureFactory.getFactory(mContext)
|
||||
.getSlicesFeatureProvider().getUiSessionToken();
|
||||
if (currentUiSession != sActiveUiSession) {
|
||||
sActiveUiSession = currentUiSession;
|
||||
sKeepSliceShow = false;
|
||||
}
|
||||
// Dark theme slice will disappear when battery saver is ON.
|
||||
if (mPowerManager.isPowerSaveMode() || (!sKeepSliceShow && !isAvailable(mContext))) {
|
||||
return new ListBuilder(mContext, CustomSliceRegistry.DARK_THEME_SLICE_URI,
|
||||
ListBuilder.INFINITY)
|
||||
.setIsError(true)
|
||||
.build();
|
||||
}
|
||||
sKeepSliceShow = true;
|
||||
final PendingIntent toggleAction = getBroadcastIntent(mContext);
|
||||
@ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
|
||||
final IconCompat icon =
|
||||
IconCompat.createWithResource(mContext, R.drawable.dark_theme);
|
||||
return new ListBuilder(mContext, CustomSliceRegistry.DARK_THEME_SLICE_URI,
|
||||
ListBuilder.INFINITY)
|
||||
.setAccentColor(color)
|
||||
.addRow(new ListBuilder.RowBuilder()
|
||||
.setTitle(mContext.getText(R.string.dark_theme_slice_title))
|
||||
.setTitleItem(icon, ICON_IMAGE)
|
||||
.setSubtitle(mContext.getText(R.string.dark_theme_slice_subtitle))
|
||||
.setPrimaryAction(
|
||||
SliceAction.createToggle(toggleAction, null /* actionTitle */,
|
||||
isDarkThemeMode(mContext))))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri getUri() {
|
||||
return CustomSliceRegistry.DARK_THEME_SLICE_URI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotifyChange(Intent intent) {
|
||||
final boolean isChecked = intent.getBooleanExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE,
|
||||
false);
|
||||
// make toggle transition more smooth before dark theme takes effect
|
||||
new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||
mUiModeManager.setNightModeActivated(isChecked);
|
||||
}, DELAY_TIME_EXECUTING_DARK_THEME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getIntent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getBackgroundWorkerClass() {
|
||||
return DarkThemeWorker.class;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean isAvailable(Context context) {
|
||||
// checking dark theme mode.
|
||||
if (isDarkThemeMode(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// checking the current battery level
|
||||
final BatteryManager batteryManager = context.getSystemService(BatteryManager.class);
|
||||
final int level = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
|
||||
Log.d(TAG, "battery level=" + level);
|
||||
return level <= BATTERY_LEVEL_THRESHOLD;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean isDarkThemeMode(Context context) {
|
||||
final int currentNightMode =
|
||||
context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
return currentNightMode == Configuration.UI_MODE_NIGHT_YES;
|
||||
}
|
||||
|
||||
public static class DarkThemeWorker extends SliceBackgroundWorker<Void> {
|
||||
private final Context mContext;
|
||||
private final ContentObserver mContentObserver =
|
||||
new ContentObserver(new Handler(Looper.getMainLooper())) {
|
||||
@Override
|
||||
public void onChange(boolean bChanged) {
|
||||
if (mContext.getSystemService(PowerManager.class).isPowerSaveMode()) {
|
||||
notifySliceChange();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public DarkThemeWorker(Context context, Uri uri) {
|
||||
super(context, uri);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSlicePinned() {
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(LOW_POWER_MODE), false /* notifyForDescendants */,
|
||||
mContentObserver);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSliceUnpinned() {
|
||||
mContext.getContentResolver().unregisterContentObserver(mContentObserver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
}
|
||||
}
|
||||
}
|
@@ -20,8 +20,6 @@ import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||
import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
|
||||
|
||||
import static com.android.settings.notification.ChannelListPreferenceController.ARG_FROM_SETTINGS;
|
||||
|
||||
import android.app.Application;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationChannelGroup;
|
||||
@@ -62,13 +60,12 @@ import com.android.settings.slices.SliceBuilderUtils;
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
@@ -135,7 +132,6 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
};
|
||||
|
||||
protected final Context mContext;
|
||||
private final ExecutorService mExecutorService;
|
||||
@VisibleForTesting
|
||||
NotificationBackend mNotificationBackend;
|
||||
private NotificationBackend.AppRow mAppRow;
|
||||
@@ -145,7 +141,6 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
public NotificationChannelSlice(Context context) {
|
||||
mContext = context;
|
||||
mNotificationBackend = new NotificationBackend();
|
||||
mExecutorService = Executors.newCachedThreadPool();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -376,9 +371,9 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
// Create tasks to get notification data for multi-channel packages.
|
||||
final List<Future<NotificationBackend.AppRow>> appRowTasks = new ArrayList<>();
|
||||
for (PackageInfo packageInfo : packageInfoList) {
|
||||
final NotificationMultiChannelAppRow future = new NotificationMultiChannelAppRow(
|
||||
final NotificationMultiChannelAppRow appRow = new NotificationMultiChannelAppRow(
|
||||
mContext, mNotificationBackend, packageInfo);
|
||||
appRowTasks.add(mExecutorService.submit(future));
|
||||
appRowTasks.add(ThreadUtils.postOnBackgroundThread(appRow));
|
||||
}
|
||||
|
||||
// Get the package which has sent at least ~10 notifications and not turn off channels.
|
||||
|
@@ -22,11 +22,8 @@ import android.os.Looper;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.telephony.data.ApnSetting;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.settings.network.MobileDataContentObserver;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
@@ -41,14 +38,14 @@ public class MmsMessagePreferenceController extends TelephonyTogglePreferenceCon
|
||||
private TelephonyManager mTelephonyManager;
|
||||
private SubscriptionManager mSubscriptionManager;
|
||||
private MobileDataContentObserver mMobileDataContentObserver;
|
||||
private SwitchPreference mPreference;
|
||||
private PreferenceScreen mScreen;
|
||||
|
||||
public MmsMessagePreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
|
||||
mMobileDataContentObserver = new MobileDataContentObserver(
|
||||
new Handler(Looper.getMainLooper()));
|
||||
mMobileDataContentObserver.setOnMobileDataChangedListener(()->updateState(mPreference));
|
||||
mMobileDataContentObserver.setOnMobileDataChangedListener(()->refreshPreference());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,15 +76,9 @@ public class MmsMessagePreferenceController extends TelephonyTogglePreferenceCon
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mPreference = screen.findPreference(getPreferenceKey());
|
||||
mScreen = screen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
preference.setVisible(isAvailable());
|
||||
((SwitchPreference) preference).setChecked(isChecked());
|
||||
}
|
||||
|
||||
public void init(int subId) {
|
||||
mSubId = subId;
|
||||
@@ -104,4 +95,10 @@ public class MmsMessagePreferenceController extends TelephonyTogglePreferenceCon
|
||||
public boolean isChecked() {
|
||||
return mTelephonyManager.isDataEnabledForApn(ApnSetting.TYPE_MMS);
|
||||
}
|
||||
|
||||
private void refreshPreference() {
|
||||
if (mScreen != null) {
|
||||
super.displayPreference(mScreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -228,16 +228,23 @@ public class MobileNetworkUtils {
|
||||
final String currentCountry = tm.getNetworkCountryIso().toLowerCase();
|
||||
final String supportedCountries =
|
||||
Settings.Global.getString(cr, Settings.Global.EUICC_SUPPORTED_COUNTRIES);
|
||||
final String unsupportedCountries =
|
||||
Settings.Global.getString(cr, Settings.Global.EUICC_UNSUPPORTED_COUNTRIES);
|
||||
|
||||
boolean inEsimSupportedCountries = false;
|
||||
if (TextUtils.isEmpty(currentCountry)) {
|
||||
inEsimSupportedCountries = true;
|
||||
} else if (!TextUtils.isEmpty(supportedCountries)) {
|
||||
final List<String> supportedCountryList =
|
||||
Arrays.asList(TextUtils.split(supportedCountries.toLowerCase(), ","));
|
||||
if (supportedCountryList.contains(currentCountry)) {
|
||||
inEsimSupportedCountries = true;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(supportedCountries)) {
|
||||
// White list is empty, use blacklist.
|
||||
Log.d(TAG, "Using blacklist unsupportedCountries=" + unsupportedCountries);
|
||||
inEsimSupportedCountries = !isEsimUnsupportedCountry(currentCountry,
|
||||
unsupportedCountries);
|
||||
} else {
|
||||
Log.d(TAG, "Using whitelist supportedCountries=" + supportedCountries);
|
||||
inEsimSupportedCountries = isEsimSupportedCountry(currentCountry, supportedCountries);
|
||||
}
|
||||
|
||||
Log.d(TAG, "inEsimSupportedCountries=" + inEsimSupportedCountries);
|
||||
|
||||
final boolean esimIgnoredDevice =
|
||||
Arrays.asList(TextUtils.split(SystemProperties.get(KEY_ESIM_CID_IGNORE, ""), ","))
|
||||
.contains(SystemProperties.get(KEY_CID, null));
|
||||
@@ -613,4 +620,24 @@ public class MobileNetworkUtils {
|
||||
}
|
||||
return tm.getNetworkOperatorName();
|
||||
}
|
||||
|
||||
private static boolean isEsimSupportedCountry(String country, String countriesListString) {
|
||||
if (TextUtils.isEmpty(country)) {
|
||||
return true;
|
||||
} else if (TextUtils.isEmpty(countriesListString)) {
|
||||
return false;
|
||||
}
|
||||
final List<String> supportedCountries =
|
||||
Arrays.asList(TextUtils.split(countriesListString.toLowerCase(), ","));
|
||||
return supportedCountries.contains(country);
|
||||
}
|
||||
|
||||
private static boolean isEsimUnsupportedCountry(String country, String countriesListString) {
|
||||
if (TextUtils.isEmpty(country) || TextUtils.isEmpty(countriesListString)) {
|
||||
return false;
|
||||
}
|
||||
final List<String> unsupportedCountries =
|
||||
Arrays.asList(TextUtils.split(countriesListString.toLowerCase(), ","));
|
||||
return unsupportedCountries.contains(country);
|
||||
}
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ import com.android.settings.R;
|
||||
import com.android.settings.accounts.AccountFeatureProvider;
|
||||
import com.android.settings.applications.ApplicationFeatureProvider;
|
||||
import com.android.settings.aware.AwareFeatureProvider;
|
||||
import com.android.settings.biometrics.face.FaceFeatureProvider;
|
||||
import com.android.settings.bluetooth.BluetoothFeatureProvider;
|
||||
import com.android.settings.dashboard.DashboardFeatureProvider;
|
||||
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
|
||||
@@ -133,6 +134,8 @@ public abstract class FeatureFactory {
|
||||
|
||||
public abstract AwareFeatureProvider getAwareFeatureProvider();
|
||||
|
||||
public abstract FaceFeatureProvider getFaceFeatureProvider();
|
||||
|
||||
public static final class FactoryNotFoundException extends RuntimeException {
|
||||
public FactoryNotFoundException(Throwable throwable) {
|
||||
super("Unable to create factory. Did you misconfigure Proguard?", throwable);
|
||||
|
@@ -30,6 +30,8 @@ import com.android.settings.applications.ApplicationFeatureProvider;
|
||||
import com.android.settings.applications.ApplicationFeatureProviderImpl;
|
||||
import com.android.settings.aware.AwareFeatureProvider;
|
||||
import com.android.settings.aware.AwareFeatureProviderImpl;
|
||||
import com.android.settings.biometrics.face.FaceFeatureProvider;
|
||||
import com.android.settings.biometrics.face.FaceFeatureProviderImpl;
|
||||
import com.android.settings.bluetooth.BluetoothFeatureProvider;
|
||||
import com.android.settings.bluetooth.BluetoothFeatureProviderImpl;
|
||||
import com.android.settings.connecteddevice.dock.DockUpdaterFeatureProviderImpl;
|
||||
@@ -84,6 +86,7 @@ public class FeatureFactoryImpl extends FeatureFactory {
|
||||
private ContextualCardFeatureProvider mContextualCardFeatureProvider;
|
||||
private BluetoothFeatureProvider mBluetoothFeatureProvider;
|
||||
private AwareFeatureProvider mAwareFeatureProvider;
|
||||
private FaceFeatureProvider mFaceFeatureProvider;
|
||||
|
||||
@Override
|
||||
public SupportFeatureProvider getSupportFeatureProvider(Context context) {
|
||||
@@ -255,4 +258,12 @@ public class FeatureFactoryImpl extends FeatureFactory {
|
||||
}
|
||||
return mAwareFeatureProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaceFeatureProvider getFaceFeatureProvider() {
|
||||
if (mFaceFeatureProvider == null) {
|
||||
mFaceFeatureProvider = new FaceFeatureProviderImpl();
|
||||
}
|
||||
return mFaceFeatureProvider;
|
||||
}
|
||||
}
|
||||
|
@@ -32,6 +32,7 @@ import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.HideNonSystemOverlayMixin;
|
||||
|
||||
/**
|
||||
* Dialog Activity to host Settings Slices.
|
||||
@@ -62,6 +63,7 @@ public class SettingsPanelActivity extends FragmentActivity {
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
createOrUpdatePanel(true /* shouldForceCreation */);
|
||||
getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -1,243 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.privacy;
|
||||
|
||||
import static android.Manifest.permission_group.CAMERA;
|
||||
import static android.Manifest.permission_group.LOCATION;
|
||||
import static android.Manifest.permission_group.MICROPHONE;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.DAYS;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.permission.PermissionControllerManager;
|
||||
import android.permission.RuntimePermissionUsageInfo;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnCreate;
|
||||
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.widget.BarChartInfo;
|
||||
import com.android.settingslib.widget.BarChartPreference;
|
||||
import com.android.settingslib.widget.BarViewInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class PermissionBarChartPreferenceController extends BasePreferenceController implements
|
||||
PermissionControllerManager.OnPermissionUsageResultCallback, LifecycleObserver, OnCreate,
|
||||
OnStart, OnSaveInstanceState {
|
||||
|
||||
private static final String TAG = "BarChartPreferenceCtl";
|
||||
private static final String KEY_PERMISSION_USAGE = "usage_infos";
|
||||
|
||||
@VisibleForTesting
|
||||
List<RuntimePermissionUsageInfo> mOldUsageInfos;
|
||||
private PackageManager mPackageManager;
|
||||
private PrivacyDashboardFragment mParent;
|
||||
private BarChartPreference mBarChartPreference;
|
||||
|
||||
public PermissionBarChartPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mOldUsageInfos = new ArrayList<>();
|
||||
mPackageManager = context.getPackageManager();
|
||||
}
|
||||
|
||||
public void setFragment(PrivacyDashboardFragment fragment) {
|
||||
mParent = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
if (savedInstanceState != null) {
|
||||
mOldUsageInfos = savedInstanceState.getParcelableArrayList(KEY_PERMISSION_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putParcelableList(KEY_PERMISSION_USAGE, mOldUsageInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return UNSUPPORTED_ON_DEVICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mBarChartPreference = screen.findPreference(getPreferenceKey());
|
||||
|
||||
final BarChartInfo info = new BarChartInfo.Builder()
|
||||
.setTitle(R.string.permission_bar_chart_title)
|
||||
.setDetails(R.string.permission_bar_chart_details)
|
||||
.setEmptyText(R.string.permission_bar_chart_empty_text)
|
||||
.setDetailsOnClickListener((View v) -> {
|
||||
final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
|
||||
intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1));
|
||||
mContext.startActivity(intent);
|
||||
})
|
||||
.build();
|
||||
|
||||
mBarChartPreference.initializeBarChart(info);
|
||||
if (!mOldUsageInfos.isEmpty()) {
|
||||
mBarChartPreference.setBarViewInfos(createBarViews(mOldUsageInfos));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
if (!isAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't hide chart when we have existing data.
|
||||
mBarChartPreference.updateLoadingState(mOldUsageInfos.isEmpty() /* isLoading */);
|
||||
// But we still need to hint user with progress bar that we are updating new usage data.
|
||||
mParent.setLoadingEnabled(true /* enabled */);
|
||||
retrievePermissionUsageData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPermissionUsageResult(@NonNull List<RuntimePermissionUsageInfo> usageInfos) {
|
||||
usageInfos.sort((x, y) -> {
|
||||
int usageDiff = y.getAppAccessCount() - x.getAppAccessCount();
|
||||
if (usageDiff != 0) {
|
||||
return usageDiff;
|
||||
}
|
||||
String xName = x.getName();
|
||||
String yName = y.getName();
|
||||
if (xName.equals(LOCATION)) {
|
||||
return -1;
|
||||
} else if (yName.equals(LOCATION)) {
|
||||
return 1;
|
||||
} else if (xName.equals(MICROPHONE)) {
|
||||
return -1;
|
||||
} else if (yName.equals(MICROPHONE)) {
|
||||
return 1;
|
||||
} else if (xName.equals(CAMERA)) {
|
||||
return -1;
|
||||
} else if (yName.equals(CAMERA)) {
|
||||
return 1;
|
||||
}
|
||||
return x.getName().compareTo(y.getName());
|
||||
});
|
||||
|
||||
// If the result is different, we need to update bar views.
|
||||
if (!areSamePermissionGroups(usageInfos)) {
|
||||
mBarChartPreference.setBarViewInfos(createBarViews(usageInfos));
|
||||
mOldUsageInfos = usageInfos;
|
||||
}
|
||||
|
||||
mBarChartPreference.updateLoadingState(false /* isLoading */);
|
||||
mParent.setLoadingEnabled(false /* enabled */);
|
||||
}
|
||||
|
||||
private void retrievePermissionUsageData() {
|
||||
mContext.getSystemService(PermissionControllerManager.class).getPermissionUsages(
|
||||
false /* countSystem */, (int) DAYS.toMillis(1),
|
||||
mContext.getMainExecutor() /* executor */, this /* callback */);
|
||||
}
|
||||
|
||||
private BarViewInfo[] createBarViews(List<RuntimePermissionUsageInfo> usageInfos) {
|
||||
if (usageInfos.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final BarViewInfo[] barViewInfos = new BarViewInfo[
|
||||
Math.min(BarChartPreference.MAXIMUM_BAR_VIEWS, usageInfos.size())];
|
||||
|
||||
for (int index = 0; index < barViewInfos.length; index++) {
|
||||
final RuntimePermissionUsageInfo permissionGroupInfo = usageInfos.get(index);
|
||||
final int count = permissionGroupInfo.getAppAccessCount();
|
||||
final CharSequence permLabel = getPermissionGroupLabel(permissionGroupInfo.getName());
|
||||
|
||||
barViewInfos[index] = new BarViewInfo(
|
||||
getPermissionGroupIcon(permissionGroupInfo.getName()), count, permLabel,
|
||||
mContext.getResources().getQuantityString(R.plurals.permission_bar_chart_label,
|
||||
count, count), permLabel);
|
||||
|
||||
// Set the click listener for each bar view.
|
||||
// The listener will navigate user to permission usage app.
|
||||
barViewInfos[index].setClickListener((View v) -> {
|
||||
final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
|
||||
intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permissionGroupInfo.getName());
|
||||
intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1));
|
||||
mContext.startActivity(intent);
|
||||
});
|
||||
}
|
||||
|
||||
return barViewInfos;
|
||||
}
|
||||
|
||||
private Drawable getPermissionGroupIcon(String permissionGroup) {
|
||||
Drawable icon = null;
|
||||
try {
|
||||
icon = mPackageManager.getPermissionGroupInfo(permissionGroup, 0)
|
||||
.loadIcon(mPackageManager);
|
||||
icon.setTintList(Utils.getColorAttr(mContext, android.R.attr.textColorSecondary));
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.w(TAG, "Cannot find group icon for " + permissionGroup, e);
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
private CharSequence getPermissionGroupLabel(String permissionGroup) {
|
||||
CharSequence label = null;
|
||||
try {
|
||||
label = mPackageManager.getPermissionGroupInfo(permissionGroup, 0)
|
||||
.loadLabel(mPackageManager);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.w(TAG, "Cannot find group label for " + permissionGroup, e);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
private boolean areSamePermissionGroups(List<RuntimePermissionUsageInfo> newUsageInfos) {
|
||||
if (newUsageInfos.size() != mOldUsageInfos.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int index = 0; index < newUsageInfos.size(); index++) {
|
||||
final RuntimePermissionUsageInfo newInfo = newUsageInfos.get(index);
|
||||
final RuntimePermissionUsageInfo oldInfo = mOldUsageInfos.get(index);
|
||||
|
||||
if (!newInfo.getName().equals(oldInfo.getName()) ||
|
||||
newInfo.getAppAccessCount() != oldInfo.getAppAccessCount()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -18,14 +18,12 @@ package com.android.settings.privacy;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.notification.LockScreenNotificationPreferenceController;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
@@ -75,34 +73,6 @@ public class PrivacyDashboardFragment extends DashboardFragment {
|
||||
return buildPreferenceControllers(context, getSettingsLifecycle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
use(PermissionBarChartPreferenceController.class).setFragment(this /* fragment */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
Utils.setActionBarShadowAnimation(getActivity(), getSettingsLifecycle(), getListView());
|
||||
initLoadingBar();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void initLoadingBar() {
|
||||
mProgressHeader = setPinnedHeaderView(R.layout.progress_header);
|
||||
mProgressAnimation = mProgressHeader.findViewById(R.id.progress_bar_animation);
|
||||
setLoadingEnabled(false);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setLoadingEnabled(boolean enabled) {
|
||||
if (mProgressHeader != null && mProgressAnimation != null) {
|
||||
mProgressHeader.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
|
||||
mProgressAnimation.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<AbstractPreferenceController> buildPreferenceControllers(
|
||||
Context context, Lifecycle lifecycle) {
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
|
@@ -37,6 +37,7 @@ import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;
|
||||
import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlice;
|
||||
import com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice;
|
||||
import com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice;
|
||||
import com.android.settings.homepage.contextualcards.slices.DarkThemeSlice;
|
||||
import com.android.settings.homepage.contextualcards.slices.FaceSetupSlice;
|
||||
import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
|
||||
import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice;
|
||||
@@ -342,6 +343,16 @@ public class CustomSliceRegistry {
|
||||
.appendPath("media_output_indicator")
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Backing Uri for the Dark theme Slice.
|
||||
*/
|
||||
public static final Uri DARK_THEME_SLICE_URI = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||
.appendPath("dark_theme")
|
||||
.build();
|
||||
|
||||
@VisibleForTesting
|
||||
static final Map<Uri, Class<? extends CustomSliceable>> sUriToSlice;
|
||||
|
||||
@@ -367,6 +378,7 @@ public class CustomSliceRegistry {
|
||||
sUriToSlice.put(NOTIFICATION_CHANNEL_SLICE_URI, NotificationChannelSlice.class);
|
||||
sUriToSlice.put(STORAGE_SLICE_URI, StorageSlice.class);
|
||||
sUriToSlice.put(WIFI_SLICE_URI, WifiSlice.class);
|
||||
sUriToSlice.put(DARK_THEME_SLICE_URI, DarkThemeSlice.class);
|
||||
}
|
||||
|
||||
public static Class<? extends CustomSliceable> getSliceClassByUri(Uri uri) {
|
||||
|
@@ -95,7 +95,7 @@ public interface CustomSliceable extends Sliceable {
|
||||
.setData(getUri())
|
||||
.setClass(context, SliceBroadcastReceiver.class);
|
||||
return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -175,7 +175,7 @@ public class SliceBuilderUtils {
|
||||
.putExtra(EXTRA_SLICE_KEY, data.getKey())
|
||||
.putExtra(EXTRA_SLICE_PLATFORM_DEFINED, data.isPlatformDefined());
|
||||
return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -310,7 +310,7 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
|
||||
mHandler.sendEmptyMessageDelayed(MESSAGE_STOP_SCAN_WIFI_LIST, DELAY_TIME_STOP_SCAN_MS);
|
||||
|
||||
if (mFilterWifiTracker == null) {
|
||||
mFilterWifiTracker = new FilterWifiTracker(getActivity(), getSettingsLifecycle());
|
||||
mFilterWifiTracker = new FilterWifiTracker(getContext(), getSettingsLifecycle());
|
||||
}
|
||||
mFilterWifiTracker.onResume();
|
||||
}
|
||||
@@ -476,11 +476,13 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
|
||||
private final class FilterWifiTracker {
|
||||
private final List<String> mAccessPointKeys;
|
||||
private final WifiTracker mWifiTracker;
|
||||
private final Context mContext;
|
||||
|
||||
public FilterWifiTracker(Context context, Lifecycle lifecycle) {
|
||||
mWifiTracker = WifiTrackerFactory.create(context, mWifiListener,
|
||||
lifecycle, /* includeSaved */ true, /* includeScans */ true);
|
||||
mAccessPointKeys = new ArrayList<>();
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -489,7 +491,7 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
|
||||
*/
|
||||
public void updateKeys(List<ScanResult> scanResults) {
|
||||
for (ScanResult scanResult : scanResults) {
|
||||
final String key = AccessPoint.getKey(scanResult);
|
||||
final String key = AccessPoint.getKey(mContext, scanResult);
|
||||
if (!mAccessPointKeys.contains(key)) {
|
||||
mAccessPointKeys.add(key);
|
||||
}
|
||||
|
@@ -583,35 +583,6 @@ public class WifiConfigController implements TextWatcher,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special handling for WPA2/WPA3 and OWE in Transition mode: The key
|
||||
* SECURITY_PSK_SAE_TRANSITION and SECURITY_OWE_TRANSITION are pseudo keys which result by the
|
||||
* scan results, but never appears in the saved networks.
|
||||
* A saved network is either WPA3 for supporting devices or WPA2 for non-supporting devices,
|
||||
* or, OWE for supporting devices or Open for non-supporting devices.
|
||||
*
|
||||
* @param accessPointSecurity Access point current security type
|
||||
* @return Converted security type (if required)
|
||||
*/
|
||||
private int convertSecurityTypeForMatching(int accessPointSecurity) {
|
||||
if (accessPointSecurity == AccessPoint.SECURITY_PSK_SAE_TRANSITION) {
|
||||
if (mWifiManager.isWpa3SaeSupported()) {
|
||||
return AccessPoint.SECURITY_SAE;
|
||||
} else {
|
||||
return AccessPoint.SECURITY_PSK;
|
||||
}
|
||||
}
|
||||
if (accessPointSecurity == AccessPoint.SECURITY_OWE_TRANSITION) {
|
||||
if (mWifiManager.isEnhancedOpenSupported()) {
|
||||
return AccessPoint.SECURITY_OWE;
|
||||
} else {
|
||||
return AccessPoint.SECURITY_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return accessPointSecurity;
|
||||
}
|
||||
|
||||
public WifiConfiguration getConfig() {
|
||||
if (mMode == WifiConfigUiBase.MODE_VIEW) {
|
||||
return null;
|
||||
@@ -634,8 +605,6 @@ public class WifiConfigController implements TextWatcher,
|
||||
|
||||
config.shared = mSharedCheckBox.isChecked();
|
||||
|
||||
mAccessPointSecurity = convertSecurityTypeForMatching(mAccessPointSecurity);
|
||||
|
||||
switch (mAccessPointSecurity) {
|
||||
case AccessPoint.SECURITY_NONE:
|
||||
config.allowedKeyManagement.set(KeyMgmt.NONE);
|
||||
@@ -960,8 +929,7 @@ public class WifiConfigController implements TextWatcher,
|
||||
|
||||
private void showSecurityFields(boolean refreshEapMethods, boolean refreshCertificates) {
|
||||
if (mAccessPointSecurity == AccessPoint.SECURITY_NONE ||
|
||||
mAccessPointSecurity == AccessPoint.SECURITY_OWE ||
|
||||
mAccessPointSecurity == AccessPoint.SECURITY_OWE_TRANSITION) {
|
||||
mAccessPointSecurity == AccessPoint.SECURITY_OWE) {
|
||||
mView.findViewById(R.id.security_fields).setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
@@ -494,9 +494,7 @@ public class WifiSettings extends RestrictedSettingsFragment
|
||||
if (isSavedNetwork) {
|
||||
connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
|
||||
} else if ((mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) ||
|
||||
(mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE) ||
|
||||
(mSelectedAccessPoint.getSecurity()
|
||||
== AccessPoint.SECURITY_OWE_TRANSITION)) {
|
||||
(mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE)) {
|
||||
/** Bypass dialog for unsecured networks */
|
||||
mSelectedAccessPoint.generateOpenNetworkConfig();
|
||||
connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
|
||||
@@ -750,8 +748,7 @@ public class WifiSettings extends RestrictedSettingsFragment
|
||||
preference.setOrder(index);
|
||||
if (mOpenSsid != null && mOpenSsid.equals(accessPoint.getSsidStr())
|
||||
&& (accessPoint.getSecurity() != AccessPoint.SECURITY_NONE &&
|
||||
accessPoint.getSecurity() != AccessPoint.SECURITY_OWE &&
|
||||
accessPoint.getSecurity() != AccessPoint.SECURITY_OWE_TRANSITION)) {
|
||||
accessPoint.getSecurity() != AccessPoint.SECURITY_OWE)) {
|
||||
if (!accessPoint.isSaved() || isDisabledByWrongPassword(accessPoint)) {
|
||||
onPreferenceTreeClick(preference);
|
||||
mOpenSsid = null;
|
||||
|
@@ -268,8 +268,7 @@ public class WifiUtils {
|
||||
if (accessPoint.isOsuProvider()) {
|
||||
return CONNECT_TYPE_OSU_PROVISION;
|
||||
} else if ((accessPoint.getSecurity() == AccessPoint.SECURITY_NONE) ||
|
||||
(accessPoint.getSecurity() == AccessPoint.SECURITY_OWE) ||
|
||||
(accessPoint.getSecurity() == AccessPoint.SECURITY_OWE_TRANSITION)) {
|
||||
(accessPoint.getSecurity() == AccessPoint.SECURITY_OWE)) {
|
||||
return CONNECT_TYPE_OPEN_NETWORK;
|
||||
} else if (accessPoint.isSaved() && config != null
|
||||
&& config.getNetworkSelectionStatus() != null
|
||||
|
@@ -206,7 +206,7 @@ public class WifiDppUtils {
|
||||
setConfiguratorIntentExtra(intent, wifiManager, wifiConfiguration);
|
||||
|
||||
// For a transition mode Wi-Fi AP, creates a QR code that's compatible with more devices
|
||||
if (accessPoint.getSecurity() == AccessPoint.SECURITY_PSK_SAE_TRANSITION) {
|
||||
if (accessPoint.isPskSaeTransitionMode()) {
|
||||
intent.putExtra(EXTRA_WIFI_SECURITY, WifiQrCode.SECURITY_WPA_PSK);
|
||||
}
|
||||
|
||||
@@ -406,7 +406,6 @@ public class WifiDppUtils {
|
||||
}
|
||||
break;
|
||||
case AccessPoint.SECURITY_PSK:
|
||||
case AccessPoint.SECURITY_PSK_SAE_TRANSITION:
|
||||
return true;
|
||||
default:
|
||||
}
|
||||
@@ -419,8 +418,6 @@ public class WifiDppUtils {
|
||||
case AccessPoint.SECURITY_PSK:
|
||||
case AccessPoint.SECURITY_WEP:
|
||||
case AccessPoint.SECURITY_NONE:
|
||||
case AccessPoint.SECURITY_PSK_SAE_TRANSITION:
|
||||
case AccessPoint.SECURITY_OWE_TRANSITION:
|
||||
return true;
|
||||
case AccessPoint.SECURITY_SAE:
|
||||
if (wifiManager.isWpa3SaeSupported()) {
|
||||
|
@@ -16,25 +16,9 @@
|
||||
|
||||
package com.android.settings.display;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.IPowerManager;
|
||||
import android.os.PowerManager;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import org.junit.Assert;
|
||||
import com.android.settings.display.darkmode.DarkModePreference;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -43,6 +27,10 @@ import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class DarkUIPreferenceControllerTest {
|
||||
|
||||
@@ -57,7 +45,7 @@ public class DarkUIPreferenceControllerTest {
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mController = spy(new DarkUIPreferenceController(mContext, "dark_ui_mode"));
|
||||
mController.setParentFragment(mFragment);
|
||||
mController.mPreference = new SwitchPreference(mContext);
|
||||
mController.mPreference = new DarkModePreference(mContext, null /* AttributeSet attrs */);
|
||||
mController.onStart();
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.display.darkmode;
|
||||
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.os.PowerManager;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.widget.LayoutPreference;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.eq;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class DarkModeActivationPreferenceControllerTest {
|
||||
private DarkModeActivationPreferenceController mController;
|
||||
private String mPreferenceKey = "key";
|
||||
@Mock
|
||||
private LayoutPreference mPreference;
|
||||
@Mock
|
||||
private PreferenceScreen mScreen;
|
||||
@Mock
|
||||
private Resources res;
|
||||
@Mock
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private UiModeManager mService;
|
||||
@Mock
|
||||
private Button mTurnOffButton;
|
||||
@Mock
|
||||
private Button mTurnOnButton;
|
||||
@Mock
|
||||
private PowerManager mPM;
|
||||
|
||||
private Configuration configNightYes = new Configuration();
|
||||
private Configuration configNightNo = new Configuration();;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mService = mock(UiModeManager.class);
|
||||
when(mContext.getResources()).thenReturn(res);
|
||||
when(mContext.getSystemService(UiModeManager.class)).thenReturn(mService);
|
||||
when(mContext.getSystemService(PowerManager.class)).thenReturn(mPM);
|
||||
when(mScreen.findPreference(anyString())).thenReturn(mPreference);
|
||||
when(mPreference.findViewById(
|
||||
eq(R.id.dark_ui_turn_on_button))).thenReturn(mTurnOnButton);
|
||||
when(mPreference.findViewById(
|
||||
eq(R.id.dark_ui_turn_off_button))).thenReturn(mTurnOffButton);
|
||||
when(mService.setNightModeActivated(anyBoolean())).thenReturn(true);
|
||||
when(mContext.getString(
|
||||
R.string.dark_ui_activation_off_auto)).thenReturn("off_auto");
|
||||
when(mContext.getString(
|
||||
R.string.dark_ui_activation_on_auto)).thenReturn("on_auto");
|
||||
when(mContext.getString(
|
||||
R.string.dark_ui_activation_off_manual)).thenReturn("off_manual");
|
||||
when(mContext.getString(
|
||||
R.string.dark_ui_activation_on_manual)).thenReturn("on_manual");
|
||||
when(mContext.getString(
|
||||
R.string.dark_ui_summary_off_auto_mode_auto)).thenReturn("summary_off_auto");
|
||||
when(mContext.getString(
|
||||
R.string.dark_ui_summary_on_auto_mode_auto)).thenReturn("summary_on_auto");
|
||||
when(mContext.getString(
|
||||
R.string.dark_ui_summary_off_auto_mode_never)).thenReturn("summary_off_manual");
|
||||
when(mContext.getString(
|
||||
R.string.dark_ui_summary_on_auto_mode_never)).thenReturn("summary_on_manual");
|
||||
mController = new DarkModeActivationPreferenceController(mContext, mPreferenceKey);
|
||||
mController.displayPreference(mScreen);
|
||||
configNightNo.uiMode = Configuration.UI_MODE_NIGHT_NO;
|
||||
configNightYes.uiMode = Configuration.UI_MODE_NIGHT_YES;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightMode_toggleButton_offManual() {
|
||||
when(mService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_YES);
|
||||
when(res.getConfiguration()).thenReturn(configNightYes);
|
||||
|
||||
mController.updateState(mPreference);
|
||||
|
||||
verify(mTurnOnButton).setVisibility(eq(View.GONE));
|
||||
verify(mTurnOffButton).setVisibility(eq(View.VISIBLE));
|
||||
verify(mTurnOffButton).setText(eq(mContext.getString(
|
||||
R.string.dark_ui_activation_off_manual)));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void nightMode_toggleButton_onAutoWhenModeIsYes() {
|
||||
when(mService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_YES);
|
||||
when(res.getConfiguration()).thenReturn(configNightNo);
|
||||
|
||||
mController.updateState(mPreference);
|
||||
|
||||
verify(mTurnOffButton).setVisibility(eq(View.GONE));
|
||||
verify(mTurnOnButton).setVisibility(eq(View.VISIBLE));
|
||||
verify(mTurnOnButton).setText(eq(mContext.getString(
|
||||
R.string.dark_ui_activation_on_manual)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightMode_toggleButton_onAutoWhenModeIsAuto() {
|
||||
when(mService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_AUTO);
|
||||
when(res.getConfiguration()).thenReturn(configNightNo);
|
||||
|
||||
mController.updateState(mPreference);
|
||||
|
||||
verify(mTurnOffButton).setVisibility(eq(View.GONE));
|
||||
verify(mTurnOnButton).setVisibility(eq(View.VISIBLE));
|
||||
verify(mTurnOnButton).setText(eq(mContext.getString(
|
||||
R.string.dark_ui_activation_on_auto)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeSummary_buttonText_onManual() {
|
||||
when(mService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_NO);
|
||||
when(res.getConfiguration()).thenReturn(configNightYes);
|
||||
|
||||
assertEquals(mController.getSummary(), mContext.getString(
|
||||
R.string.dark_ui_summary_on_auto_mode_never));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeSummary_buttonText_offAuto() {
|
||||
when(mService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_AUTO);
|
||||
when(res.getConfiguration()).thenReturn(configNightNo);
|
||||
|
||||
assertEquals(mController.getSummary(), mContext.getString(
|
||||
R.string.dark_ui_summary_off_auto_mode_auto));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buttonVisisbility_hideButton_offWhenInPowerSaveMode() {
|
||||
when(mPM.isPowerSaveMode()).thenReturn(true);
|
||||
mController.updateState(mPreference);
|
||||
verify(mTurnOffButton).setVisibility(eq(View.GONE));
|
||||
verify(mTurnOnButton).setVisibility(eq(View.GONE));
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.display.darkmode;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.provider.Settings;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class DarkModeObserverTest {
|
||||
private Context mContext;
|
||||
private ContentObserver mContentObserver;
|
||||
private DarkModeObserver mDarkModeObserver;
|
||||
private Runnable mCallback;
|
||||
private Uri mUri = Settings.Secure.getUriFor(Settings.Secure.UI_NIGHT_MODE);
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mDarkModeObserver = new DarkModeObserver(mContext);
|
||||
mContentObserver = mDarkModeObserver.getContentObserver();
|
||||
mCallback = mock(Runnable.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callbackTest_subscribedCallbackCalled() {
|
||||
mDarkModeObserver.subscribe(mCallback);
|
||||
mContentObserver.onChange(false, mUri);
|
||||
Mockito.verify(mCallback, times(2)).run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void callbackTest_unsubscribedCallNotbackCalled() {
|
||||
mDarkModeObserver.subscribe(mCallback);
|
||||
mContentObserver.onChange(false, mUri);
|
||||
mDarkModeObserver.unsubscribe();
|
||||
mContentObserver.onChange(false, mUri);
|
||||
Mockito.verify(mCallback, times(2)).run();
|
||||
}
|
||||
}
|
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.display.darkmode;
|
||||
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
import android.os.PowerManager;
|
||||
import androidx.preference.DropDownPreference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import com.android.settings.R;
|
||||
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class DarkModeScheduleSelectorControllerTest {
|
||||
private DarkModeScheduleSelectorController mController;
|
||||
private String mPreferenceKey = "key";
|
||||
@Mock
|
||||
private DropDownPreference mPreference;
|
||||
@Mock
|
||||
private PreferenceScreen mScreen;
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private UiModeManager mUiService;
|
||||
@Mock
|
||||
private PowerManager mPM;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
when(mContext.getSystemService(UiModeManager.class)).thenReturn(mUiService);
|
||||
when(mContext.getSystemService(PowerManager.class)).thenReturn(mPM);
|
||||
when(mContext.getString(R.string.dark_ui_auto_mode_never)).thenReturn("never");
|
||||
when(mContext.getString(R.string.dark_ui_auto_mode_auto)).thenReturn("auto");
|
||||
mPreference = spy(new DropDownPreference(mContext));
|
||||
when(mScreen.findPreference(anyString())).thenReturn(mPreference);
|
||||
when(mUiService.setNightModeActivated(anyBoolean())).thenReturn(true);
|
||||
mController = new DarkModeScheduleSelectorController(mContext, mPreferenceKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightMode_preferenceChange_preferenceChangeTrueWhenChangedOnly() {
|
||||
when(mUiService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_YES);
|
||||
mController.displayPreference(mScreen);
|
||||
boolean changed = mController
|
||||
.onPreferenceChange(mScreen, mContext.getString(R.string.dark_ui_auto_mode_auto));
|
||||
assertTrue(changed);
|
||||
changed = mController
|
||||
.onPreferenceChange(mScreen, mContext.getString(R.string.dark_ui_auto_mode_auto));
|
||||
assertFalse(changed);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightMode_updateStateNone_dropDownValueChangedToNone() {
|
||||
when(mUiService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_YES);
|
||||
mController.displayPreference(mScreen);
|
||||
mController.updateState(mPreference);
|
||||
verify(mPreference).setValue(mContext.getString(R.string.dark_ui_auto_mode_never));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightMode_updateStateNone_dropDownValueChangedToAuto() {
|
||||
when(mUiService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_AUTO);
|
||||
mController.displayPreference(mScreen);
|
||||
mController.updateState(mPreference);
|
||||
verify(mPreference).setValue(mContext.getString(R.string.dark_ui_auto_mode_auto));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void batterySaver_dropDown_disabledSelector() {
|
||||
when(mPM.isPowerSaveMode()).thenReturn(true);
|
||||
mController.displayPreference(mScreen);
|
||||
mController.updateState(mPreference);
|
||||
verify(mPreference).setEnabled(eq(false));
|
||||
}
|
||||
}
|
@@ -85,7 +85,6 @@ public class BatteryHeaderPreferenceControllerTest {
|
||||
private BatteryMeterView mBatteryMeterView;
|
||||
private TextView mBatteryPercentText;
|
||||
private TextView mSummary;
|
||||
private TextView mSummary2;
|
||||
private LayoutPreference mBatteryLayoutPref;
|
||||
private Intent mBatteryIntent;
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
@@ -102,7 +101,6 @@ public class BatteryHeaderPreferenceControllerTest {
|
||||
mBatteryPercentText = new TextView(mContext);
|
||||
mSummary = new TextView(mContext);
|
||||
ShadowEntityHeaderController.setUseMock(mEntityHeaderController);
|
||||
mSummary2 = new TextView(mContext);
|
||||
|
||||
mBatteryIntent = new Intent();
|
||||
mBatteryIntent.putExtra(BatteryManager.EXTRA_LEVEL, BATTERY_LEVEL);
|
||||
@@ -126,7 +124,6 @@ public class BatteryHeaderPreferenceControllerTest {
|
||||
mController.mBatteryMeterView = mBatteryMeterView;
|
||||
mController.mBatteryPercentText = mBatteryPercentText;
|
||||
mController.mSummary1 = mSummary;
|
||||
mController.mSummary2 = mSummary2;
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -190,7 +187,6 @@ public class BatteryHeaderPreferenceControllerTest {
|
||||
@Test
|
||||
public void quickUpdateHeaderPreference_onlyUpdateBatteryLevelAndChargingState() {
|
||||
mSummary.setText(BATTERY_STATUS);
|
||||
mSummary2.setText(BATTERY_STATUS);
|
||||
|
||||
mController.quickUpdateHeaderPreference();
|
||||
|
||||
@@ -198,7 +194,6 @@ public class BatteryHeaderPreferenceControllerTest {
|
||||
assertThat(mBatteryMeterView.getCharging()).isTrue();
|
||||
assertThat(mBatteryPercentText.getText().toString()).isEqualTo("60 %");
|
||||
assertThat(mSummary.getText()).isEqualTo(BATTERY_STATUS);
|
||||
assertThat(mSummary2.getText()).isEqualTo(BATTERY_STATUS);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@@ -265,20 +265,17 @@ public class PowerUsageSummaryTest {
|
||||
}
|
||||
}).when(mFeatureFactory.powerUsageFeatureProvider).getEnhancedEstimateDebugString(any());
|
||||
|
||||
doReturn(new TextView(mRealContext)).when(mBatteryLayoutPref).findViewById(R.id.summary2);
|
||||
doReturn(new TextView(mRealContext)).when(mBatteryLayoutPref).findViewById(R.id.summary1);
|
||||
mFragment.onLongClick(new View(mRealContext));
|
||||
TextView summary1 = mFragment.mBatteryLayoutPref.findViewById(R.id.summary1);
|
||||
TextView summary2 = mFragment.mBatteryLayoutPref.findViewById(R.id.summary2);
|
||||
Robolectric.flushBackgroundThreadScheduler();
|
||||
assertThat(summary2.getText().toString()).contains(NEW_ML_EST_SUFFIX);
|
||||
assertThat(summary1.getText().toString()).contains(NEW_ML_EST_SUFFIX);
|
||||
assertThat(summary1.getText().toString()).contains(OLD_EST_SUFFIX);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void debugMode() {
|
||||
doReturn(true).when(mFeatureFactory.powerUsageFeatureProvider).isEstimateDebugEnabled();
|
||||
doReturn(new TextView(mRealContext)).when(mBatteryLayoutPref).findViewById(R.id.summary2);
|
||||
|
||||
mFragment.restartBatteryInfoLoader();
|
||||
ArgumentCaptor<View.OnLongClickListener> listener = ArgumentCaptor.forClass(
|
||||
|
@@ -16,20 +16,42 @@
|
||||
|
||||
package com.android.settings.homepage;
|
||||
|
||||
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.HideNonSystemOverlayMixin;
|
||||
import com.android.settings.homepage.contextualcards.slices.BatteryFixSliceTest;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.android.controller.ActivityController;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class SettingsHomepageActivityTest {
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setHomepageContainerPaddingTop_shouldBeSetPaddingTop() {
|
||||
@@ -55,4 +77,55 @@ public class SettingsHomepageActivityTest {
|
||||
|
||||
assertThat(frameLayout.getLayoutTransition()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {
|
||||
BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
|
||||
BatteryFixSliceTest.ShadowBatteryTipLoader.class
|
||||
})
|
||||
public void onStart_isNotDebuggable_shouldHideSystemOverlay() {
|
||||
ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false);
|
||||
|
||||
final ActivityController<SettingsHomepageActivity> activityController =
|
||||
Robolectric.buildActivity(SettingsHomepageActivity.class).create();
|
||||
final SettingsHomepageActivity activity = spy(activityController.get());
|
||||
final Window window = mock(Window.class);
|
||||
when(activity.getWindow()).thenReturn(window);
|
||||
activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity));
|
||||
|
||||
activityController.start();
|
||||
|
||||
verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {
|
||||
BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
|
||||
BatteryFixSliceTest.ShadowBatteryTipLoader.class,
|
||||
})
|
||||
public void onStop_isNotDebuggable_shouldRemoveHideSystemOverlay() {
|
||||
ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false);
|
||||
|
||||
final ActivityController<SettingsHomepageActivity> activityController =
|
||||
Robolectric.buildActivity(SettingsHomepageActivity.class).create();
|
||||
final SettingsHomepageActivity activity = spy(activityController.get());
|
||||
final Window window = mock(Window.class);
|
||||
when(activity.getWindow()).thenReturn(window);
|
||||
activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity));
|
||||
|
||||
activityController.start();
|
||||
|
||||
verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
|
||||
|
||||
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
|
||||
when(window.getAttributes()).thenReturn(layoutParams);
|
||||
|
||||
activityController.stop();
|
||||
final ArgumentCaptor<WindowManager.LayoutParams> paramCaptor = ArgumentCaptor.forClass(
|
||||
WindowManager.LayoutParams.class);
|
||||
|
||||
verify(window).setAttributes(paramCaptor.capture());
|
||||
assertThat(paramCaptor.getValue().privateFlags
|
||||
& SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(0);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.homepage.contextualcards.slices;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.PowerManager;
|
||||
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.SliceMetadata;
|
||||
import androidx.slice.SliceProvider;
|
||||
import androidx.slice.widget.SliceLiveData;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.slices.CustomSliceRegistry;
|
||||
import com.android.settings.slices.SlicesFeatureProviderImpl;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class DarkThemeSliceTest {
|
||||
@Mock
|
||||
private BatteryManager mBatteryManager;
|
||||
@Mock
|
||||
private PowerManager mPowerManager;
|
||||
|
||||
private Context mContext;
|
||||
private DarkThemeSlice mDarkThemeSlice;
|
||||
private FakeFeatureFactory mFeatureFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||
mFeatureFactory.slicesFeatureProvider = new SlicesFeatureProviderImpl();
|
||||
mFeatureFactory.slicesFeatureProvider.newUiSession();
|
||||
doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
|
||||
when(mPowerManager.isPowerSaveMode()).thenReturn(false);
|
||||
|
||||
// Set-up specs for SliceMetadata.
|
||||
SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
|
||||
mDarkThemeSlice = spy(new DarkThemeSlice(mContext));
|
||||
mDarkThemeSlice.sKeepSliceShow = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUri_shouldBeDarkThemeSliceUri() {
|
||||
final Uri uri = mDarkThemeSlice.getUri();
|
||||
|
||||
assertThat(uri).isEqualTo(CustomSliceRegistry.DARK_THEME_SLICE_URI);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_inDarkThemeMode_returnFalse() {
|
||||
doReturn(true).when(mDarkThemeSlice).isDarkThemeMode(mContext);
|
||||
|
||||
assertThat(mDarkThemeSlice.isAvailable(mContext)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_nonDarkThemeBatteryCapacityEq100_returnFalse() {
|
||||
setBatteryCapacityLevel(100);
|
||||
|
||||
assertThat(mDarkThemeSlice.isAvailable(mContext)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_nonDarkThemeBatteryCapacityLt50_returnTrue() {
|
||||
setBatteryCapacityLevel(40);
|
||||
|
||||
assertThat(mDarkThemeSlice.isAvailable(mContext)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSlice_batterySaver_returnErrorSlice() {
|
||||
when(mPowerManager.isPowerSaveMode()).thenReturn(true);
|
||||
|
||||
final Slice mediaSlice = mDarkThemeSlice.getSlice();
|
||||
final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice);
|
||||
assertThat(metadata.isErrorSlice()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSlice_notAvailable_returnErrorSlice() {
|
||||
doReturn(true).when(mDarkThemeSlice).isDarkThemeMode(mContext);
|
||||
|
||||
final Slice mediaSlice = mDarkThemeSlice.getSlice();
|
||||
final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice);
|
||||
assertThat(metadata.isErrorSlice()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSlice_newSession_notAvailable_returnErrorSlice() {
|
||||
// previous displayed: yes
|
||||
mDarkThemeSlice.sKeepSliceShow = true;
|
||||
// Session: use original value + 1 to become a new session
|
||||
mDarkThemeSlice.sActiveUiSession =
|
||||
mFeatureFactory.slicesFeatureProvider.getUiSessionToken() + 1;
|
||||
|
||||
doReturn(true).when(mDarkThemeSlice).isDarkThemeMode(mContext);
|
||||
|
||||
final Slice mediaSlice = mDarkThemeSlice.getSlice();
|
||||
final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice);
|
||||
assertThat(metadata.isErrorSlice()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSlice_previouslyDisplayed_isAvailable_returnSlice() {
|
||||
mDarkThemeSlice.sActiveUiSession =
|
||||
mFeatureFactory.slicesFeatureProvider.getUiSessionToken();
|
||||
mDarkThemeSlice.sKeepSliceShow = true;
|
||||
setBatteryCapacityLevel(40);
|
||||
|
||||
assertThat(mDarkThemeSlice.getSlice()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSlice_isAvailable_returnSlice() {
|
||||
setBatteryCapacityLevel(40);
|
||||
|
||||
assertThat(mDarkThemeSlice.getSlice()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSlice_isAvailable_showTitleSubtitle() {
|
||||
setBatteryCapacityLevel(40);
|
||||
|
||||
final Slice slice = mDarkThemeSlice.getSlice();
|
||||
final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
|
||||
assertThat(metadata.getTitle()).isEqualTo(
|
||||
mContext.getString(R.string.dark_theme_slice_title));
|
||||
assertThat(metadata.getSubtitle()).isEqualTo(
|
||||
mContext.getString(R.string.dark_theme_slice_subtitle));
|
||||
}
|
||||
|
||||
private void setBatteryCapacityLevel(int power_level) {
|
||||
doReturn(false).when(mDarkThemeSlice).isDarkThemeMode(mContext);
|
||||
doReturn(mBatteryManager).when(mContext).getSystemService(BatteryManager.class);
|
||||
when(mBatteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY))
|
||||
.thenReturn(power_level);
|
||||
}
|
||||
}
|
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.settings.panel;
|
||||
|
||||
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
|
||||
|
||||
import static com.android.settings.panel.SettingsPanelActivity.KEY_MEDIA_PACKAGE_NAME;
|
||||
import static com.android.settings.panel.SettingsPanelActivity.KEY_PANEL_TYPE_ARGUMENT;
|
||||
|
||||
@@ -28,17 +30,23 @@ import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Intent;
|
||||
import android.view.MotionEvent;
|
||||
import android.os.Build;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.settings.core.HideNonSystemOverlayMixin;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.android.controller.ActivityController;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class SettingsPanelActivityTest {
|
||||
@@ -50,6 +58,7 @@ public class SettingsPanelActivityTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||
mSettingsPanelActivity = spy(
|
||||
Robolectric.buildActivity(FakeSettingsPanelActivity.class).create().get());
|
||||
@@ -87,4 +96,47 @@ public class SettingsPanelActivityTest {
|
||||
assertThat(activity.mBundle.getString(KEY_PANEL_TYPE_ARGUMENT))
|
||||
.isEqualTo("com.android.settings.panel.action.MEDIA_OUTPUT");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_isNotDebuggable_shouldHideSystemOverlay() {
|
||||
ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false);
|
||||
|
||||
final ActivityController<SettingsPanelActivity> activityController =
|
||||
Robolectric.buildActivity(SettingsPanelActivity.class).create();
|
||||
final SettingsPanelActivity activity = spy(activityController.get());
|
||||
final Window window = mock(Window.class);
|
||||
when(activity.getWindow()).thenReturn(window);
|
||||
activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity));
|
||||
|
||||
activityController.start();
|
||||
|
||||
verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_isNotDebuggable_shouldRemoveHideSystemOverlay() {
|
||||
ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false);
|
||||
|
||||
final ActivityController<SettingsPanelActivity> activityController =
|
||||
Robolectric.buildActivity(SettingsPanelActivity.class).create();
|
||||
final SettingsPanelActivity activity = spy(activityController.get());
|
||||
final Window window = mock(Window.class);
|
||||
when(activity.getWindow()).thenReturn(window);
|
||||
activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity));
|
||||
|
||||
activityController.start();
|
||||
|
||||
verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
|
||||
|
||||
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
|
||||
when(window.getAttributes()).thenReturn(layoutParams);
|
||||
|
||||
activityController.stop();
|
||||
final ArgumentCaptor<WindowManager.LayoutParams> paramCaptor = ArgumentCaptor.forClass(
|
||||
WindowManager.LayoutParams.class);
|
||||
|
||||
verify(window).setAttributes(paramCaptor.capture());
|
||||
assertThat(paramCaptor.getValue().privateFlags
|
||||
& SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(0);
|
||||
}
|
||||
}
|
||||
|
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.privacy;
|
||||
|
||||
import static android.Manifest.permission_group.CALENDAR;
|
||||
import static android.Manifest.permission_group.CAMERA;
|
||||
import static android.Manifest.permission_group.CONTACTS;
|
||||
import static android.Manifest.permission_group.LOCATION;
|
||||
import static android.Manifest.permission_group.MICROPHONE;
|
||||
import static android.Manifest.permission_group.PHONE;
|
||||
import static android.Manifest.permission_group.SMS;
|
||||
|
||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
|
||||
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.UserManager;
|
||||
import android.permission.RuntimePermissionUsageInfo;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.shadow.ShadowDeviceConfig;
|
||||
import com.android.settings.testutils.shadow.ShadowPermissionControllerManager;
|
||||
import com.android.settings.testutils.shadow.ShadowUserManager;
|
||||
import com.android.settingslib.widget.BarChartInfo;
|
||||
import com.android.settingslib.widget.BarChartPreference;
|
||||
import com.android.settingslib.widget.BarViewInfo;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.shadows.ShadowAccessibilityManager;
|
||||
import org.robolectric.shadows.androidx.fragment.FragmentController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowDeviceConfig.class, ShadowUserManager.class,
|
||||
ShadowPermissionControllerManager.class})
|
||||
public class PermissionBarChartPreferenceControllerTest {
|
||||
|
||||
@Mock
|
||||
private PreferenceScreen mScreen;
|
||||
@Mock
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
|
||||
private PermissionBarChartPreferenceController mController;
|
||||
private BarChartPreference mPreference;
|
||||
private PrivacyDashboardFragment mFragment;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
final Context context = RuntimeEnvironment.application;
|
||||
final UserManager userManager = context.getSystemService(UserManager.class);
|
||||
final ShadowUserManager shadowUserManager = Shadow.extract(userManager);
|
||||
final ShadowAccessibilityManager accessibilityManager = Shadow.extract(
|
||||
AccessibilityManager.getInstance(context));
|
||||
accessibilityManager.setEnabledAccessibilityServiceList(new ArrayList<>());
|
||||
shadowUserManager.addProfile(new UserInfo(123, null, 0));
|
||||
when(FakeFeatureFactory.setupForTest().securityFeatureProvider.getLockPatternUtils(
|
||||
any(Context.class))).thenReturn(mLockPatternUtils);
|
||||
|
||||
mController = spy(new PermissionBarChartPreferenceController(context, "test_key"));
|
||||
mFragment = spy(FragmentController.of(new PrivacyDashboardFragment())
|
||||
.create().start().get());
|
||||
mController.setFragment(mFragment);
|
||||
mPreference = spy(new BarChartPreference(context));
|
||||
when(mScreen.findPreference(mController.getPreferenceKey()))
|
||||
.thenReturn((BarChartPreference) mPreference);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowDeviceConfig.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_permissionHubNotSet_shouldReturnUnsupported() {
|
||||
// We have not yet set the property to show the Permissions Hub.
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
}
|
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.privacy;
|
||||
|
||||
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;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserManager;
|
||||
import android.permission.PermissionControllerManager;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.shadow.ShadowPermissionControllerManager;
|
||||
import com.android.settings.testutils.shadow.ShadowUserManager;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
import org.robolectric.shadows.ShadowAccessibilityManager;
|
||||
import org.robolectric.shadows.androidx.fragment.FragmentController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowUserManager.class, ShadowPermissionControllerManager.class})
|
||||
public class PrivacyDashboardFragmentTest {
|
||||
|
||||
@Mock
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
@Mock
|
||||
private PermissionControllerManager mPCM;
|
||||
|
||||
private Context mContext;
|
||||
private PrivacyDashboardFragment mFragment;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
final UserManager userManager = mContext.getSystemService(UserManager.class);
|
||||
final ShadowUserManager shadowUserManager = Shadow.extract(userManager);
|
||||
final ShadowAccessibilityManager accessibilityManager = Shadow.extract(
|
||||
AccessibilityManager.getInstance(mContext));
|
||||
accessibilityManager.setEnabledAccessibilityServiceList(new ArrayList<>());
|
||||
shadowUserManager.addProfile(new UserInfo(123, null, 0));
|
||||
when(FakeFeatureFactory.setupForTest().securityFeatureProvider.getLockPatternUtils(
|
||||
any(Context.class))).thenReturn(mLockPatternUtils);
|
||||
mFragment = spy(FragmentController.of(new PrivacyDashboardFragment())
|
||||
.create().start().get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onViewCreated_shouldSetActionBarShadowAnimation() {
|
||||
mFragment.onViewCreated(new View(mContext), new Bundle());
|
||||
|
||||
assertThat(mFragment.getActivity().getActionBar().getElevation()).isEqualTo(0.f);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onViewCreated_shouldInitLinearProgressBar() {
|
||||
mFragment.onViewCreated(new View(mContext), new Bundle());
|
||||
|
||||
verify(mFragment).initLoadingBar();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateLinearProgressbar_isVisible_shouldShowProgressBar() {
|
||||
mFragment.setLoadingEnabled(true /* enabled */);
|
||||
|
||||
assertThat(mFragment.mProgressHeader.getVisibility()).isEqualTo(View.VISIBLE);
|
||||
assertThat(mFragment.mProgressAnimation.getVisibility()).isEqualTo(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateLinearProgressbar_isInVisible_shouldHideProgressBar() {
|
||||
mFragment.setLoadingEnabled(false /* enabled */);
|
||||
|
||||
assertThat(mFragment.mProgressHeader.getVisibility()).isEqualTo(View.INVISIBLE);
|
||||
assertThat(mFragment.mProgressAnimation.getVisibility()).isEqualTo(View.INVISIBLE);
|
||||
}
|
||||
}
|
@@ -24,6 +24,7 @@ import android.content.Context;
|
||||
import com.android.settings.accounts.AccountFeatureProvider;
|
||||
import com.android.settings.applications.ApplicationFeatureProvider;
|
||||
import com.android.settings.aware.AwareFeatureProvider;
|
||||
import com.android.settings.biometrics.face.FaceFeatureProvider;
|
||||
import com.android.settings.bluetooth.BluetoothFeatureProvider;
|
||||
import com.android.settings.dashboard.DashboardFeatureProvider;
|
||||
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
|
||||
@@ -68,6 +69,7 @@ public class FakeFeatureFactory extends FeatureFactory {
|
||||
public final ContextualCardFeatureProvider mContextualCardFeatureProvider;
|
||||
public final BluetoothFeatureProvider mBluetoothFeatureProvider;
|
||||
public final AwareFeatureProvider mAwareFeatureProvider;
|
||||
public final FaceFeatureProvider mFaceFeatureProvider;
|
||||
|
||||
public PanelFeatureProvider panelFeatureProvider;
|
||||
public SlicesFeatureProvider slicesFeatureProvider;
|
||||
@@ -114,6 +116,7 @@ public class FakeFeatureFactory extends FeatureFactory {
|
||||
panelFeatureProvider = mock(PanelFeatureProvider.class);
|
||||
mBluetoothFeatureProvider = mock(BluetoothFeatureProvider.class);
|
||||
mAwareFeatureProvider = mock(AwareFeatureProvider.class);
|
||||
mFaceFeatureProvider = mock(FaceFeatureProvider.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -215,4 +218,9 @@ public class FakeFeatureFactory extends FeatureFactory {
|
||||
public AwareFeatureProvider getAwareFeatureProvider() {
|
||||
return mAwareFeatureProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaceFeatureProvider getFaceFeatureProvider() {
|
||||
return mFaceFeatureProvider;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user