Snap for 5189750 from abcfa26bf6 to qt-release
Change-Id: I170cbec6d76999499b14011158b65e906d30322c
This commit is contained in:
@@ -14,6 +14,7 @@ include $(CLEAR_VARS)
|
||||
LOCAL_PACKAGE_NAME := Settings
|
||||
LOCAL_PRIVATE_PLATFORM_APIS := true
|
||||
LOCAL_CERTIFICATE := platform
|
||||
LOCAL_PRODUCT_MODULE := true
|
||||
LOCAL_PRIVILEGED_MODULE := true
|
||||
LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.settings
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
@@ -717,8 +717,7 @@
|
||||
android:name="Settings$ZenModeSettingsActivity"
|
||||
android:label="@string/zen_mode_settings_title"
|
||||
android:icon="@drawable/ic_notifications"
|
||||
android:exported="true"
|
||||
android:parentActivityName="Settings">
|
||||
android:exported="true">
|
||||
<intent-filter android:priority="1">
|
||||
<action android:name="android.settings.ZEN_MODE_SETTINGS" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
@@ -875,8 +874,7 @@
|
||||
android:name="Settings$NightDisplaySettingsActivity"
|
||||
android:label="@string/night_display_title"
|
||||
android:enabled="@*android:bool/config_nightDisplayAvailable"
|
||||
android:icon="@drawable/ic_settings_night_display"
|
||||
android:parentActivityName="Settings">
|
||||
android:icon="@drawable/ic_settings_night_display">
|
||||
<intent-filter android:priority="32">
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="com.android.settings.SHORTCUT" />
|
||||
@@ -1626,7 +1624,7 @@
|
||||
android:icon="@drawable/ic_settings_security">
|
||||
<intent-filter android:priority="1">
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="com.android.settings.suggested.category.LOCK_SCREEN" />
|
||||
<category android:name="com.android.settings.suggested.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="com.android.settings.title"
|
||||
android:resource="@string/suggested_lock_settings_title" />
|
||||
@@ -2821,10 +2819,8 @@
|
||||
android:name=".Settings$AppAndNotificationDashboardActivity"
|
||||
android:label="@string/app_and_notification_dashboard_title"
|
||||
android:icon="@drawable/ic_homepage_apps"
|
||||
android:parentActivityName="Settings">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.settings.action.SETTINGS"/>
|
||||
</intent-filter>
|
||||
android:parentActivityName="Settings"
|
||||
android:exported="true">
|
||||
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
|
||||
android:value="com.android.settings.applications.AppAndNotificationDashboardFragment"/>
|
||||
</activity>
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Settings_intermediates)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Settings_intermediates)
|
||||
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/Settings)
|
||||
|
||||
# ************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
|
||||
|
||||
3
OWNERS
3
OWNERS
@@ -7,8 +7,11 @@ asargent@google.com
|
||||
dehboxturtle@google.com
|
||||
dhnishi@google.com
|
||||
dling@google.com
|
||||
edgarwang@google.com
|
||||
jackqdyulei@google.com
|
||||
mfritze@google.com
|
||||
rafftsai@google.com
|
||||
tmfang@google.com
|
||||
zhfan@google.com
|
||||
|
||||
# Emergency approvers in case the above are not available
|
||||
|
||||
@@ -43,8 +43,5 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<include layout="@layout/wifi_dpp_fragment_footer"
|
||||
android:gravity="center|bottom"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -39,6 +39,6 @@
|
||||
style="@style/SuwGlifButton.Primary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/suw_next_button_label" />
|
||||
android:text="@string/wizard_next" />
|
||||
|
||||
</com.google.android.setupdesign.view.ButtonBarLayout>
|
||||
|
||||
@@ -39,6 +39,6 @@
|
||||
style="@style/SuwGlifButton.Primary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/suw_next_button_label" />
|
||||
android:text="@string/wizard_next" />
|
||||
|
||||
</com.google.android.setupdesign.view.ButtonBarLayout>
|
||||
|
||||
29
res/layout/slice_preference_layout.xml
Normal file
29
res/layout/slice_preference_layout.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
|
||||
<androidx.slice.widget.SliceView
|
||||
android:id="@+id/slice_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
</FrameLayout>
|
||||
@@ -27,7 +27,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:onClick="onNavigateBack"
|
||||
android:visibility="gone"
|
||||
android:text="@string/suw_back_button_label" />
|
||||
android:text="@string/wizard_back" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -41,6 +41,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:onClick="onNavigateNext"
|
||||
android:visibility="gone"
|
||||
android:text="@string/suw_next_button_label" />
|
||||
android:text="@string/wizard_next" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -22,12 +22,6 @@
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_wifi_signal_4"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -17,18 +17,42 @@
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
style="@style/EntityHeader"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:layout_centerHorizontal="true"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp">
|
||||
|
||||
<TextView android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"/>
|
||||
<ImageView
|
||||
android:id="@+id/header_icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:scaleType="fitCenter"/>
|
||||
|
||||
<TextView android:id="@+id/description"
|
||||
android:layout_width="wrap_content"
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextAppearance.EntityHeaderTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"/>
|
||||
android:gravity="center_horizontal"
|
||||
android:textAlignment="center"
|
||||
android:layout_marginTop="8dp"
|
||||
android:paddingStart="32dp"
|
||||
android:paddingEnd="32dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
style="@style/TextAppearance.EntityHeaderSummary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="false"
|
||||
android:gravity="center_horizontal"
|
||||
android:textAlignment="center"
|
||||
android:layout_marginTop="2dp"
|
||||
android:paddingStart="32dp"
|
||||
android:paddingEnd="32dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
|
||||
<attr name="apnPreferenceStyle" format="reference" />
|
||||
|
||||
<attr name="slicePreferenceStyle" format="reference" />
|
||||
|
||||
<attr name="footerPreferenceStyle" format="reference" />
|
||||
|
||||
<declare-styleable name="FixedLineSummaryPreference">
|
||||
|
||||
@@ -165,4 +165,7 @@
|
||||
|
||||
<!-- Email address for the homepage contextual cards feedback -->
|
||||
<string name="config_contextual_card_feedback_email" translatable="false"></string>
|
||||
|
||||
<!-- Uri that represents extra bluetooth settings -->
|
||||
<string name="config_bluetooth_device_settings_uri" translatable="false">content://com.google.android.gms.nearby.fastpair/settings_slice?addr=<xliff:g id="mac_address">%1$s</xliff:g></string>
|
||||
</resources>
|
||||
|
||||
@@ -827,8 +827,15 @@
|
||||
<string name="location_settings_title">Location</string>
|
||||
<!-- Used in the location settings to control turning on/off the feature entirely -->
|
||||
<string name="location_settings_master_switch_title">Use location</string>
|
||||
<!-- Summary for Location settings, explaining a few important settings under it [CHAR LIMIT=NONE]-->
|
||||
<string name="location_settings_summary">Scanning, location history</string>
|
||||
<!-- Summary for Location settings when location is off [CHAR LIMIT=NONE] -->
|
||||
<string name="location_settings_summary_location_off">Off</string>
|
||||
<!-- Summary for Location settings when location is on, explaining how many apps have location permission [CHAR LIMIT=NONE]-->
|
||||
<plurals name="location_settings_summary_location_on">
|
||||
<item quantity="one">On - <xliff:g id="count">%1$d</xliff:g> app can access location</item>
|
||||
<item quantity="other">On - <xliff:g id="count">%1$d</xliff:g> apps can access location</item>
|
||||
</plurals>
|
||||
<!-- Location settings, loading the number of apps which have location permission [CHAR LIMIT=30] -->
|
||||
<string name="location_settings_loading_app_permission_stats">Loading\u2026</string>
|
||||
|
||||
<!-- Main Settings screen setting option title for the item to take you to the accounts screen [CHAR LIMIT=22] -->
|
||||
<string name="account_settings_title">Accounts</string>
|
||||
@@ -3630,15 +3637,28 @@
|
||||
<string name="managed_profile_location_switch_title">Location for work profile</string>
|
||||
<!-- [CHAR LIMIT=30] Location settings screen. It's a link that directs the user to a page that
|
||||
shows the location permission setting for each installed app -->
|
||||
<string name="location_app_level_permissions">App-level permissions</string>
|
||||
<!-- [CHAR LIMIT=42] Location settings screen, sub category for recent location requests -->
|
||||
<string name="location_category_recent_location_requests">Recent location requests</string>
|
||||
<!-- Location settings screen, displayed when there're more than three recent location requests -->
|
||||
<string name="location_recent_location_requests_see_all">See all</string>
|
||||
<string name="location_app_level_permissions">App permission</string>
|
||||
<!-- Summary for app permission on Location settings page when location is off [CHAR LIMIT=NONE] -->
|
||||
<string name="location_app_permission_summary_location_off">Location is off</string>
|
||||
<!-- Summary for Location settings when location is on, explaining how many apps have location permission [CHAR LIMIT=NONE]-->
|
||||
<plurals name="location_app_permission_summary_location_on">
|
||||
<item quantity="one">
|
||||
<xliff:g id="background_location_app_count">%1$d</xliff:g>
|
||||
of
|
||||
<xliff:g id="total_location_app_count">%2$d</xliff:g>
|
||||
app has unlimited access</item>
|
||||
<item quantity="other">
|
||||
<xliff:g id="background_location_app_count">%1$d</xliff:g>
|
||||
of
|
||||
<xliff:g id="total_location_app_count">%2$d</xliff:g>
|
||||
apps have unlimited access</item>
|
||||
</plurals>
|
||||
<!-- [CHAR LIMIT=50] Location settings screen, sub category for recent location access -->
|
||||
<string name="location_category_recent_location_access">Recent location access</string>
|
||||
<!-- [CHAR LIMIT=30] Location settings screen, button to bring the user to view the details of recent location access -->
|
||||
<string name="location_recent_location_access_view_details">View details</string>
|
||||
<!-- Location settings screen, displayed when there's no recent app accessing location -->
|
||||
<string name="location_no_recent_apps">No apps have requested location recently</string>
|
||||
<!-- [CHAR LIMIT=30] Location settings screen, sub category for location services -->
|
||||
<string name="location_category_location_services">Location services</string>
|
||||
<!-- [CHAR LIMIT=30] Location settings screen, recent location requests high battery use-->
|
||||
<string name="location_high_battery_use">High battery use</string>
|
||||
<!-- [CHAR LIMIT=30] Location settings screen, recent location requests low battery use-->
|
||||
@@ -6746,7 +6766,7 @@
|
||||
<string name="wizard_back">Back</string>
|
||||
<!-- Wizard next button label [CHAR LIMIT=25] -->
|
||||
<string name="wizard_next">Next</string>
|
||||
<!-- Wizard next button label [CHAR LIMIT=25] -->
|
||||
<!-- Wizard finish button label [CHAR LIMIT=25] -->
|
||||
<string name="wizard_finish">Finish</string>
|
||||
|
||||
<!-- An option in a photo selection dialog, if there is no photo yet [CHAR LIMIT=50] -->
|
||||
@@ -6943,6 +6963,8 @@
|
||||
<string name="keywords_sim_status">network, mobile network state, service state, signal strength, mobile network type, roaming, iccid</string>
|
||||
<string name="keywords_model_and_hardware">serial number, hardware version</string>
|
||||
<string name="keywords_android_version">android security patch level, baseband version, kernel version</string>
|
||||
<!--Search keywords for financial apps sms access settings -->
|
||||
<string name="keywords_financial_apps_sms_access">financial app, sms, permission</string>
|
||||
|
||||
<!-- Search keyword for Device Theme Settings [CHAR LIMIT=NONE] -->
|
||||
<string name="keywords_systemui_theme">dark theme</string>
|
||||
@@ -8833,6 +8855,10 @@
|
||||
<!-- Summary of number of apps currently can write system settings [CHAR LIMIT=60] -->
|
||||
<string name="write_settings_summary"><xliff:g id="count" example="10">%1$d</xliff:g> of <xliff:g id="count" example="10">%2$d</xliff:g> apps allowed to modify system settings</string>
|
||||
|
||||
<!-- Settings title in main settings screen for financial apps sms access [CHAR LIMIT=60] -->
|
||||
<string name="financial_apps_sms_access_title">Financial Apps Sms Access</string>
|
||||
<!-- Preference key for financial apps sms access screen -->
|
||||
<string name="financial_sms_root_screen_key" translatable="false">financial_sms_root_screen_key</string>
|
||||
<!-- Label for showing apps that can install other apps [CHAR LIMIT=45] -->
|
||||
<string name="filter_install_sources_apps">Can install other apps</string>
|
||||
<!-- Label for showing apps that can write system settings [CHAR LIMIT=45] -->
|
||||
|
||||
@@ -489,4 +489,8 @@
|
||||
<item name="android:textAllCaps">false</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.SliceView.Settings">
|
||||
<item name="titleSize">@*android:dimen/text_size_subhead_material</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
<style name="PreferenceTheme" parent="@style/PreferenceThemeOverlay.SettingsBase">
|
||||
<item name="apnPreferenceStyle">@style/ApnPreference</item>
|
||||
<item name="slicePreferenceStyle">@style/SlicePreference</item>
|
||||
<item name="seekBarPreferenceStyle">@style/SettingsSeekBarPreference</item>
|
||||
<item name="twoStateButtonPreferenceStyle">@style/TwoStateButtonPreference</item>
|
||||
</style>
|
||||
@@ -34,6 +35,10 @@
|
||||
<item name="android:layout">@layout/apn_preference_layout</item>
|
||||
</style>
|
||||
|
||||
<style name="SlicePreference" parent="@style/Preference.Material">
|
||||
<item name="android:layout">@layout/slice_preference_layout</item>
|
||||
</style>
|
||||
|
||||
<style name="SettingsSeekBarPreference" parent="@style/Preference.Material">
|
||||
<item name="android:layout">@layout/preference_widget_seekbar_settings</item>
|
||||
</style>
|
||||
|
||||
@@ -32,9 +32,13 @@
|
||||
<item name="fingerprint_layout_theme">@style/FingerprintLayoutTheme</item>
|
||||
<item name="face_layout_theme">@style/FaceLayoutTheme</item>
|
||||
<item name="ic_menu_moreoverflow">@*android:drawable/ic_menu_moreoverflow_holo_dark</item>
|
||||
|
||||
<!-- For wifi icon -->
|
||||
<item name="wifi_signal">@drawable/wifi_signal</item>
|
||||
<item name="wifi_signal_color">?android:attr/colorAccent</item>
|
||||
<item name="wifi_friction">@drawable/wifi_friction</item>
|
||||
<item name="frictionIconColor">?android:colorControlNormal</item>
|
||||
|
||||
<item name="side_margin">@dimen/settings_side_margin</item>
|
||||
<item name="suwListItemIconColor">?android:attr/colorAccent</item>
|
||||
|
||||
@@ -58,6 +62,9 @@
|
||||
<!-- TODO(118444000): Remove colorPrimary and colorPrimaryVariant -->
|
||||
<item name="colorPrimary">@*android:color/primary_device_default_settings_light</item>
|
||||
<item name="colorPrimaryVariant">@android:color/white</item>
|
||||
|
||||
<!-- For slice view in settings -->
|
||||
<item name="sliceViewStyle">@style/Widget.SliceView.Settings</item>
|
||||
</style>
|
||||
|
||||
<!-- Variant of the settings theme with no action bar. -->
|
||||
@@ -71,9 +78,6 @@
|
||||
<item name="android:actionBarStyle">@style/Widget.ActionBar.SubSettings</item>
|
||||
|
||||
<item name="switchBarTheme">@style/ThemeOverlay.SwitchBar.Settings</item>
|
||||
|
||||
<!-- Friction icon color for wifi preferences -->
|
||||
<item name="frictionIconColor">?android:colorControlNormal</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.SubSettings" parent="Theme.SubSettings.Base"/>
|
||||
|
||||
@@ -26,7 +26,14 @@
|
||||
settings:allowDividerBelow="true"/>
|
||||
|
||||
<com.android.settingslib.widget.ActionButtonsPreference
|
||||
android:key="action_buttons" />
|
||||
android:key="action_buttons"
|
||||
settings:allowDividerBelow="true"/>
|
||||
|
||||
<com.android.settings.slices.SlicePreference
|
||||
android:key="bt_device_slice"
|
||||
settings:controller="com.android.settings.slices.SlicePreferenceController"
|
||||
settings:allowDividerBelow="true"
|
||||
settings:allowDividerAbove="true"/>
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="bluetooth_profiles"/>
|
||||
|
||||
@@ -9,16 +9,14 @@
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:title="@string/location_category_recent_location_requests"
|
||||
android:key="recent_location_requests_see_all">
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="all_recent_location_requests"/>
|
||||
</PreferenceScreen>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:key="@string/financial_sms_root_screen_key"
|
||||
android:title="@string/financial_apps_sms_access_title"
|
||||
settings:controller="com.android.settings.applications.specialaccess.financialapps.FinancialAppsController" />
|
||||
@@ -20,21 +20,14 @@
|
||||
android:title="@string/location_settings_title"
|
||||
settings:keywords="@string/keywords_location">
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="recent_location_requests"
|
||||
android:title="@string/location_category_recent_location_requests"/>
|
||||
|
||||
<Preference
|
||||
android:key="recent_location_requests_see_all_button"
|
||||
android:title="@string/location_recent_location_requests_see_all"
|
||||
android:icon="@drawable/ic_chevron_right_24dp"
|
||||
android:selectable="true"
|
||||
android:fragment="com.android.settings.location.RecentLocationRequestSeeAllFragment"
|
||||
settings:searchable="false"/>
|
||||
<com.android.settingslib.widget.LayoutPreference
|
||||
android:key="apps_dashboard"
|
||||
android:layout="@layout/app_entities_header"
|
||||
settings:allowDividerBelow="true" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="location_advanced_settings"
|
||||
settings:initialExpandedChildrenCount="1">
|
||||
settings:initialExpandedChildrenCount="0">
|
||||
|
||||
<!-- This preference category gets removed if new_recent_location_ui is disabled -->
|
||||
<Preference
|
||||
@@ -60,8 +53,7 @@
|
||||
android:selectable="true" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="location_services"
|
||||
android:title="@string/location_category_location_services"/>
|
||||
android:key="location_services" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
|
||||
@@ -130,4 +130,9 @@
|
||||
android:value="com.android.settings.Settings$ChangeWifiStateActivity" />
|
||||
</Preference>
|
||||
|
||||
<Preference
|
||||
android:key="financial_apps_sms_access"
|
||||
android:title="@string/financial_apps_sms_access_title"
|
||||
android:fragment="com.android.settings.applications.specialaccess.financialapps.FinancialAppsSmsAccess"
|
||||
settings:keywords="@string/keywords_financial_apps_sms_access" />
|
||||
</PreferenceScreen>
|
||||
|
||||
@@ -93,10 +93,11 @@
|
||||
<Preference
|
||||
android:key="top_level_location"
|
||||
android:title="@string/location_settings_title"
|
||||
android:summary="@string/location_settings_summary"
|
||||
android:summary="@string/location_settings_loading_app_permission_stats"
|
||||
android:icon="@drawable/ic_homepage_location"
|
||||
android:order="-50"
|
||||
android:fragment="com.android.settings.location.LocationSettings"/>
|
||||
android:fragment="com.android.settings.location.LocationSettings"
|
||||
settings:controller="com.android.settings.location.TopLevelLocationPreferenceController"/>
|
||||
|
||||
<Preference
|
||||
android:key="top_level_security"
|
||||
@@ -149,4 +150,4 @@
|
||||
android:order="100"
|
||||
settings:controller="com.android.settings.support.SupportPreferenceController"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
</PreferenceScreen>
|
||||
|
||||
@@ -32,7 +32,6 @@ import com.android.settings.display.TapToWakePreferenceController;
|
||||
import com.android.settings.display.ThemePreferenceController;
|
||||
import com.android.settings.display.TimeoutPreferenceController;
|
||||
import com.android.settings.display.VrDisplayPreferenceController;
|
||||
import com.android.settings.display.WallpaperPreferenceController;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.search.Indexable;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
|
||||
@@ -66,7 +66,9 @@ import com.android.settings.password.ConfirmLockPattern;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
|
||||
import com.google.android.setupcompat.TemplateLayout;
|
||||
import com.google.android.setupdesign.template.ButtonFooterMixin;
|
||||
import com.google.android.setupcompat.item.FooterButton;
|
||||
import com.google.android.setupcompat.item.FooterButton.ButtonType;
|
||||
import com.google.android.setupcompat.template.ButtonFooterMixin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -96,7 +98,7 @@ public class MasterClear extends InstrumentedFragment implements OnGlobalLayoutL
|
||||
|
||||
private View mContentView;
|
||||
@VisibleForTesting
|
||||
Button mInitiateButton;
|
||||
FooterButton mInitiateButton;
|
||||
private View mExternalStorageContainer;
|
||||
@VisibleForTesting
|
||||
CheckBox mExternalStorage;
|
||||
@@ -416,12 +418,15 @@ public class MasterClear extends InstrumentedFragment implements OnGlobalLayoutL
|
||||
|
||||
final TemplateLayout layout = mContentView.findViewById(R.id.setup_wizard_layout);
|
||||
final ButtonFooterMixin buttonFooterMixin = layout.getMixin(ButtonFooterMixin.class);
|
||||
buttonFooterMixin.removeAllViews();
|
||||
buttonFooterMixin.addSpace();
|
||||
buttonFooterMixin.addSpace();
|
||||
mInitiateButton = buttonFooterMixin.addButton(R.string.master_clear_button_text,
|
||||
R.style.SuwGlifButton_Primary);
|
||||
mInitiateButton.setOnClickListener(mInitiateListener);
|
||||
buttonFooterMixin.setPrimaryButton(
|
||||
new FooterButton(
|
||||
getActivity(),
|
||||
R.string.master_clear_button_text,
|
||||
mInitiateListener,
|
||||
ButtonType.OTHER,
|
||||
R.style.SuwGlifButton_Primary)
|
||||
);
|
||||
mInitiateButton = buttonFooterMixin.getPrimaryButton();
|
||||
}
|
||||
|
||||
private void getContentDescription(View v, StringBuffer description) {
|
||||
|
||||
@@ -45,7 +45,9 @@ import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
|
||||
import com.google.android.setupcompat.TemplateLayout;
|
||||
import com.google.android.setupdesign.template.ButtonFooterMixin;
|
||||
import com.google.android.setupcompat.item.FooterButton;
|
||||
import com.google.android.setupcompat.item.FooterButton.ButtonType;
|
||||
import com.google.android.setupcompat.template.ButtonFooterMixin;
|
||||
|
||||
/**
|
||||
* Confirm and execute a reset of the device to a clean "just out of the box"
|
||||
@@ -153,11 +155,14 @@ public class MasterClearConfirm extends InstrumentedFragment {
|
||||
final TemplateLayout layout = mContentView.findViewById(R.id.setup_wizard_layout);
|
||||
|
||||
final ButtonFooterMixin buttonFooterMixin = layout.getMixin(ButtonFooterMixin.class);
|
||||
buttonFooterMixin.removeAllViews();
|
||||
buttonFooterMixin.addSpace();
|
||||
buttonFooterMixin.addSpace();
|
||||
buttonFooterMixin.addButton(R.string.master_clear_button_text,
|
||||
R.style.SuwGlifButton_Primary).setOnClickListener(mFinalClickListener);
|
||||
buttonFooterMixin.setPrimaryButton(
|
||||
new FooterButton(
|
||||
getActivity(),
|
||||
R.string.master_clear_button_text,
|
||||
mFinalClickListener,
|
||||
ButtonType.OTHER,
|
||||
R.style.SuwGlifButton_Primary)
|
||||
);
|
||||
}
|
||||
|
||||
private void setUpActionBarAndTitle() {
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.applications.specialaccess.financialapps;
|
||||
|
||||
import static android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS;
|
||||
import static android.Manifest.permission.READ_SMS;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.Preference.OnPreferenceChangeListener;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FinancialAppsController extends BasePreferenceController
|
||||
implements ApplicationsState.Callbacks {
|
||||
private final static String TAG = FinancialAppsController.class.getSimpleName();
|
||||
|
||||
@VisibleForTesting
|
||||
PreferenceScreen mRoot;
|
||||
|
||||
public FinancialAppsController(Context context, String key) {
|
||||
super(context, key);
|
||||
}
|
||||
|
||||
@AvailabilityStatus
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mRoot = screen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
mRoot.removeAll();
|
||||
|
||||
final PackageManager packageManager = mContext.getPackageManager();
|
||||
final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
|
||||
|
||||
final List<PackageInfo> installedPackages =
|
||||
packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS);
|
||||
final int numPackages = installedPackages.size();
|
||||
for (int i = 0; i < numPackages; i++) {
|
||||
final PackageInfo installedPackage = installedPackages.get(i);
|
||||
|
||||
if (installedPackage.requestedPermissions == null) {
|
||||
continue;
|
||||
}
|
||||
final int targetSdk = installedPackage.applicationInfo.targetSdkVersion;
|
||||
final String pkgName = installedPackage.packageName;
|
||||
|
||||
if ((targetSdk >= Build.VERSION_CODES.Q
|
||||
&& ArrayUtils.contains(installedPackage.requestedPermissions,
|
||||
SMS_FINANCIAL_TRANSACTIONS))
|
||||
|| (targetSdk < Build.VERSION_CODES.Q
|
||||
&& ArrayUtils.contains(installedPackage.requestedPermissions,
|
||||
READ_SMS))) {
|
||||
final SwitchPreference pref = new SwitchPreference(mRoot.getContext());
|
||||
pref.setTitle(installedPackage.applicationInfo.loadLabel(packageManager));
|
||||
pref.setKey(pkgName);
|
||||
|
||||
pref.setChecked(
|
||||
appOpsManager.checkOp(
|
||||
targetSdk >= Build.VERSION_CODES.Q
|
||||
? AppOpsManager.OP_SMS_FINANCIAL_TRANSACTIONS
|
||||
: AppOpsManager.OP_READ_SMS,
|
||||
installedPackage.applicationInfo.uid,
|
||||
pkgName) == AppOpsManager.MODE_ALLOWED);
|
||||
|
||||
pref.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
final int uid;
|
||||
try {
|
||||
uid = packageManager.getPackageInfo(preference.getKey(), 0)
|
||||
.applicationInfo.uid;
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.e(TAG, "onPreferenceChange: Failed to get uid for "
|
||||
+ preference.getKey());
|
||||
return false;
|
||||
}
|
||||
|
||||
appOpsManager.setMode(
|
||||
targetSdk >= Build.VERSION_CODES.Q
|
||||
? AppOpsManager.OP_SMS_FINANCIAL_TRANSACTIONS
|
||||
: AppOpsManager.OP_READ_SMS,
|
||||
uid,
|
||||
pkgName,
|
||||
(Boolean) newValue ? AppOpsManager.MODE_ALLOWED
|
||||
: AppOpsManager.MODE_IGNORED);
|
||||
return true;
|
||||
});
|
||||
mRoot.addPreference(pref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRunningStateChanged(boolean running) {}
|
||||
|
||||
@Override
|
||||
public void onPackageListChanged() {
|
||||
updateList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRebuildComplete(ArrayList<AppEntry> apps) {}
|
||||
|
||||
@Override
|
||||
public void onPackageIconChanged() {}
|
||||
|
||||
@Override
|
||||
public void onPackageSizeChanged(String packageName) {}
|
||||
|
||||
@Override
|
||||
public void onAllSizesComputed() {}
|
||||
|
||||
@Override
|
||||
public void onLauncherInfoChanged() {}
|
||||
|
||||
@Override
|
||||
public void onLoadEntriesCompleted() {}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.applications.specialaccess.financialapps;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.search.Indexable;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SearchIndexable
|
||||
public class FinancialAppsSmsAccess extends DashboardFragment {
|
||||
private final static String TAG = FinancialAppsSmsAccess.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.financial_app_sms_access;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.SETTINGS_FINANCIAL_APPS_SMS_ACCESS;
|
||||
}
|
||||
|
||||
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider() {
|
||||
@Override
|
||||
public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
|
||||
boolean enabled) {
|
||||
final ArrayList<SearchIndexableResource> result = new ArrayList<>();
|
||||
|
||||
final SearchIndexableResource sir = new SearchIndexableResource(context);
|
||||
sir.xmlResId = R.xml.financial_app_sms_access;
|
||||
result.add(sir);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -67,8 +67,11 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity
|
||||
*/
|
||||
public static final int RESULT_TIMEOUT = RESULT_FIRST_USER + 2;
|
||||
|
||||
public static final int CONFIRM_REQUEST = 1;
|
||||
public static final int ENROLLING = 2;
|
||||
public static final int CHOOSE_LOCK_GENERIC_REQUEST = 1;
|
||||
public static final int BIOMETRIC_FIND_SENSOR_REQUEST = 2;
|
||||
public static final int LEARN_MORE_REQUEST = 3;
|
||||
public static final int CONFIRM_REQUEST = 4;
|
||||
public static final int ENROLLING = 5;
|
||||
|
||||
protected boolean mLaunchedConfirmLock;
|
||||
protected byte[] mToken;
|
||||
@@ -105,10 +108,6 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity
|
||||
initViews();
|
||||
}
|
||||
|
||||
protected boolean shouldLaunchConfirmLock() {
|
||||
return mToken == null && !mLaunchedConfirmLock;
|
||||
}
|
||||
|
||||
protected void initViews() {
|
||||
getWindow().setStatusBarColor(Color.TRANSPARENT);
|
||||
Button nextButton = getNextButton();
|
||||
|
||||
@@ -37,10 +37,6 @@ import com.google.android.setupdesign.span.LinkSpan;
|
||||
public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
implements LinkSpan.OnClickListener {
|
||||
|
||||
public static final int CHOOSE_LOCK_GENERIC_REQUEST = 1;
|
||||
public static final int BIOMETRIC_FIND_SENSOR_REQUEST = 2;
|
||||
public static final int LEARN_MORE_REQUEST = 3;
|
||||
|
||||
private UserManager mUserManager;
|
||||
private boolean mHasPassword;
|
||||
private boolean mBiometricUnlockDisabledByAdmin;
|
||||
@@ -109,6 +105,11 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
*/
|
||||
protected abstract Intent getEnrollingIntent();
|
||||
|
||||
/**
|
||||
* @return the title to be shown on the ConfirmLock screen.
|
||||
*/
|
||||
protected abstract int getConfirmLockTitleResId();
|
||||
|
||||
/**
|
||||
* @param span
|
||||
*/
|
||||
@@ -133,6 +134,13 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
|
||||
mUserManager = UserManager.get(this);
|
||||
updatePasswordQuality();
|
||||
|
||||
if (!mHasPassword) {
|
||||
// No password registered, launch into enrollment wizard.
|
||||
launchChooseLock();
|
||||
} else {
|
||||
launchConfirmLock(getConfirmLockTitleResId(), getChallenge());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,13 +165,8 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
|
||||
@Override
|
||||
protected void onNextButtonClick() {
|
||||
if (!mHasPassword) {
|
||||
// No biometrics registered, launch into enrollment wizard.
|
||||
launchChooseLock();
|
||||
} else {
|
||||
// Lock thingy is already set up, launch directly into find sensor step from wizard.
|
||||
launchFindSensor(null);
|
||||
}
|
||||
// Lock thingy is already set up, launch directly to the next page
|
||||
launchNextEnrollingActivity(mToken);
|
||||
}
|
||||
|
||||
private void launchChooseLock() {
|
||||
@@ -181,7 +184,7 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST);
|
||||
}
|
||||
|
||||
private void launchFindSensor(byte[] token) {
|
||||
private void launchNextEnrollingActivity(byte[] token) {
|
||||
Intent intent = getEnrollingIntent();
|
||||
if (token != null) {
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
|
||||
@@ -199,9 +202,9 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
final boolean isResultFinished = resultCode == RESULT_FINISHED;
|
||||
final int result = isResultFinished ? RESULT_OK : RESULT_SKIP;
|
||||
if (requestCode == BIOMETRIC_FIND_SENSOR_REQUEST) {
|
||||
if (isResultFinished || resultCode == RESULT_SKIP) {
|
||||
final int result = isResultFinished ? RESULT_OK : RESULT_SKIP;
|
||||
setResult(result, data);
|
||||
finish();
|
||||
return;
|
||||
@@ -209,10 +212,21 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
} else if (requestCode == CHOOSE_LOCK_GENERIC_REQUEST) {
|
||||
if (isResultFinished) {
|
||||
updatePasswordQuality();
|
||||
byte[] token = data.getByteArrayExtra(
|
||||
mToken = data.getByteArrayExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
|
||||
launchFindSensor(token);
|
||||
overridePendingTransition(R.anim.suw_slide_next_in, R.anim.suw_slide_next_out);
|
||||
return;
|
||||
} else {
|
||||
setResult(result, data);
|
||||
finish();
|
||||
}
|
||||
} else if (requestCode == CONFIRM_REQUEST) {
|
||||
if (resultCode == RESULT_OK && data != null) {
|
||||
mToken = data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
|
||||
overridePendingTransition(R.anim.suw_slide_next_in, R.anim.suw_slide_next_out);
|
||||
} else {
|
||||
setResult(result, data);
|
||||
finish();
|
||||
}
|
||||
} else if (requestCode == LEARN_MORE_REQUEST) {
|
||||
overridePendingTransition(R.anim.suw_slide_back_in, R.anim.suw_slide_back_out);
|
||||
|
||||
@@ -48,13 +48,6 @@ public abstract class BiometricsEnrollEnrolling extends BiometricEnrollBase
|
||||
*/
|
||||
protected abstract boolean shouldStartAutomatically();
|
||||
|
||||
/**
|
||||
* @return true if enrollment should finish when onStop is called.
|
||||
*/
|
||||
protected boolean shouldFinishOnStop() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
@@ -70,7 +63,7 @@ public abstract class BiometricsEnrollEnrolling extends BiometricEnrollBase
|
||||
mSidecar.setListener(null);
|
||||
}
|
||||
|
||||
if (shouldFinishOnStop() && !isChangingConfigurations()) {
|
||||
if (!isChangingConfigurations()) {
|
||||
if (mSidecar != null) {
|
||||
mSidecar.cancelEnrollment();
|
||||
getSupportFragmentManager()
|
||||
|
||||
@@ -44,7 +44,6 @@ public class FaceEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
|
||||
private TextView mErrorText;
|
||||
private Interpolator mLinearOutSlowInInterpolator;
|
||||
private boolean mShouldFinishOnStop = true;
|
||||
private FaceEnrollPreviewFragment mPreviewFragment;
|
||||
|
||||
private FaceFeatureProvider.Listener mListener = new FaceFeatureProvider.Listener() {
|
||||
@@ -92,13 +91,7 @@ public class FaceEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
Button skipButton = findViewById(R.id.skip_button);
|
||||
skipButton.setOnClickListener(this);
|
||||
|
||||
if (shouldLaunchConfirmLock()) {
|
||||
launchConfirmLock(R.string.security_settings_face_preference_title,
|
||||
Utils.getFaceManagerOrNull(this).generateChallenge());
|
||||
mShouldFinishOnStop = false;
|
||||
} else {
|
||||
startEnrollment();
|
||||
}
|
||||
startEnrollment();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,11 +122,6 @@ public class FaceEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldFinishOnStop() {
|
||||
return mShouldFinishOnStop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return MetricsProto.MetricsEvent.FACE_ENROLL_ENROLLING;
|
||||
@@ -178,23 +166,6 @@ public class FaceEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == CONFIRM_REQUEST) {
|
||||
if (resultCode == RESULT_OK && data != null) {
|
||||
mShouldFinishOnStop = true;
|
||||
mToken = data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
|
||||
overridePendingTransition(R.anim.suw_slide_next_in, R.anim.suw_slide_next_out);
|
||||
getIntent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
|
||||
startEnrollment();
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
} else {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
private void showErrorDialog(CharSequence msg, int msgId) {
|
||||
BiometricErrorDialog dialog = FaceErrorDialog.newInstance(msg, msgId);
|
||||
dialog.show(getSupportFragmentManager(), FaceErrorDialog.class.getName());
|
||||
|
||||
@@ -102,6 +102,7 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
|
||||
@Override
|
||||
protected long getChallenge() {
|
||||
mFaceManager = Utils.getFaceManagerOrNull(this);
|
||||
if (mFaceManager == null) {
|
||||
return 0;
|
||||
}
|
||||
@@ -118,6 +119,11 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
return new Intent(this, FaceEnrollEnrolling.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getConfirmLockTitleResId() {
|
||||
return R.string.security_settings_face_preference_title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return MetricsProto.MetricsEvent.FACE_ENROLL_INTRO;
|
||||
|
||||
@@ -51,12 +51,9 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase {
|
||||
|
||||
setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title);
|
||||
|
||||
if (shouldLaunchConfirmLock()) {
|
||||
launchConfirmLock(R.string.security_settings_fingerprint_preference_title,
|
||||
Utils.getFingerprintManagerOrNull(this).preEnroll());
|
||||
} else if (mToken != null) {
|
||||
startLookingForFingerprint(); // already confirmed, so start looking for fingerprint
|
||||
}
|
||||
|
||||
startLookingForFingerprint(); // already confirmed, so start looking for fingerprint
|
||||
|
||||
View animationView = findViewById(R.id.fingerprint_sensor_location_animation);
|
||||
if (animationView instanceof FingerprintFindSensorAnimation) {
|
||||
mAnimation = (FingerprintFindSensorAnimation) animationView;
|
||||
|
||||
@@ -106,6 +106,7 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
|
||||
@Override
|
||||
protected long getChallenge() {
|
||||
mFingerprintManager = Utils.getFingerprintManagerOrNull(this);
|
||||
if (mFingerprintManager == null) {
|
||||
return 0;
|
||||
}
|
||||
@@ -122,6 +123,11 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
return new Intent(this, FingerprintEnrollFindSensor.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getConfirmLockTitleResId() {
|
||||
return R.string.security_settings_fingerprint_preference_title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return MetricsProto.MetricsEvent.FINGERPRINT_ENROLL_INTRO;
|
||||
|
||||
@@ -21,12 +21,16 @@ import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.FeatureFlagUtils;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.FeatureFlags;
|
||||
import com.android.settings.dashboard.RestrictedDashboardFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.slices.SlicePreferenceController;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
@@ -98,6 +102,13 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
|
||||
mManager = getLocalBluetoothManager(context);
|
||||
mCachedDevice = getCachedDevice(mDeviceAddress);
|
||||
super.onAttach(context);
|
||||
|
||||
if (FeatureFlagUtils.isEnabled(context, FeatureFlags.SLICE_INJECTION)) {
|
||||
final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(context)
|
||||
.getBluetoothFeatureProvider(context);
|
||||
use(SlicePreferenceController.class).setSliceUri(
|
||||
featureProvider.getBluetoothDeviceSettingsUri(mDeviceAddress));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.bluetooth;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
/**
|
||||
* Provider for bluetooth related feature
|
||||
*/
|
||||
public interface BluetoothFeatureProvider {
|
||||
|
||||
/**
|
||||
* Get the {@link Uri} that represents extra settings for a specific bluetooth device
|
||||
* @param macAddress Bluetooth mac address
|
||||
* @return {@link Uri} for extra settings
|
||||
*/
|
||||
Uri getBluetoothDeviceSettingsUri(String macAddress);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.bluetooth;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
/**
|
||||
* Impl of {@link BluetoothFeatureProvider}
|
||||
*/
|
||||
public class BluetoothFeatureProviderImpl implements BluetoothFeatureProvider {
|
||||
|
||||
private Context mContext;
|
||||
|
||||
public BluetoothFeatureProviderImpl(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri getBluetoothDeviceSettingsUri(String macAddress) {
|
||||
final String uriString = mContext.getString(R.string.config_bluetooth_device_settings_uri,
|
||||
macAddress);
|
||||
return Uri.parse(uriString);
|
||||
}
|
||||
}
|
||||
@@ -27,4 +27,5 @@ public class FeatureFlags {
|
||||
public static final String WIFI_MAC_RANDOMIZATION = "settings_wifi_mac_randomization";
|
||||
public static final String NETWORK_INTERNET_V2 = "settings_network_and_internet_v2";
|
||||
public static final String WIFI_SHARING = "settings_wifi_sharing";
|
||||
public static final String SLICE_INJECTION = "settings_slice_injection";
|
||||
}
|
||||
|
||||
@@ -295,7 +295,13 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
|
||||
if (!controller.isAvailable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String key = controller.getPreferenceKey();
|
||||
if (TextUtils.isEmpty(key)) {
|
||||
Log.d(TAG, String.format("Preference key is %s in Controller %s",
|
||||
key, controller.getClass().getSimpleName()));
|
||||
continue;
|
||||
}
|
||||
|
||||
final Preference preference = screen.findPreference(key);
|
||||
if (preference == null) {
|
||||
|
||||
@@ -35,6 +35,7 @@ import androidx.loader.content.Loader;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -56,7 +57,9 @@ import java.util.stream.Collectors;
|
||||
* get the page refreshed.
|
||||
*/
|
||||
public class ContextualCardManager implements ContextualCardLoader.CardContentLoaderListener,
|
||||
ContextualCardUpdateListener {
|
||||
ContextualCardUpdateListener, LifecycleObserver, OnSaveInstanceState {
|
||||
|
||||
private static final String KEY_CONTEXTUAL_CARDS = "key_contextual_cards";
|
||||
|
||||
private static final String TAG = "ContextualCardManager";
|
||||
|
||||
@@ -68,6 +71,9 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
||||
final List<ContextualCard> mContextualCards;
|
||||
@VisibleForTesting
|
||||
long mStartTime;
|
||||
boolean mIsFirstLaunch;
|
||||
@VisibleForTesting
|
||||
List<String> mSavedCards;
|
||||
|
||||
private final Context mContext;
|
||||
private final ControllerRendererPool mControllerRendererPool;
|
||||
@@ -76,12 +82,20 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
||||
|
||||
private ContextualCardUpdateListener mListener;
|
||||
|
||||
public ContextualCardManager(Context context, Lifecycle lifecycle) {
|
||||
public ContextualCardManager(Context context, Lifecycle lifecycle, Bundle savedInstanceState) {
|
||||
mContext = context;
|
||||
mLifecycle = lifecycle;
|
||||
mContextualCards = new ArrayList<>();
|
||||
mLifecycleObservers = new ArrayList<>();
|
||||
mControllerRendererPool = new ControllerRendererPool();
|
||||
mLifecycle.addObserver(this);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
mIsFirstLaunch = true;
|
||||
mSavedCards = null;
|
||||
} else {
|
||||
mSavedCards = savedInstanceState.getStringArrayList(KEY_CONTEXTUAL_CARDS);
|
||||
}
|
||||
//for data provided by Settings
|
||||
for (@ContextualCard.CardType int cardType : SETTINGS_CARDS) {
|
||||
setupController(cardType);
|
||||
@@ -172,13 +186,34 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
||||
@Override
|
||||
public void onFinishCardLoading(List<ContextualCard> cards) {
|
||||
final long loadTime = System.currentTimeMillis() - mStartTime;
|
||||
final List<ContextualCard> cardsToKeep = getCardsToKeep(cards);
|
||||
|
||||
//navigate back to the homepage or after card dismissal
|
||||
if (!mIsFirstLaunch) {
|
||||
onContextualCardUpdated(cardsToKeep.stream()
|
||||
.collect(groupingBy(ContextualCard::getCardType)));
|
||||
return;
|
||||
}
|
||||
|
||||
//only log homepage display upon a fresh launch
|
||||
if (loadTime <= ContextualCardLoader.CARD_CONTENT_LOADER_TIMEOUT_MS) {
|
||||
onContextualCardUpdated(
|
||||
cards.stream().collect(groupingBy(ContextualCard::getCardType)));
|
||||
onContextualCardUpdated(cards.stream()
|
||||
.collect(groupingBy(ContextualCard::getCardType)));
|
||||
}
|
||||
final long totalTime = System.currentTimeMillis() - mStartTime;
|
||||
FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider()
|
||||
.logHomepageDisplay(mContext, totalTime);
|
||||
|
||||
mIsFirstLaunch = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
final ArrayList<String> cards = mContextualCards.stream()
|
||||
.map(ContextualCard::getName)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
|
||||
outState.putStringArrayList(KEY_CONTEXTUAL_CARDS, cards);
|
||||
}
|
||||
|
||||
public ControllerRendererPool getControllerRendererPool() {
|
||||
@@ -189,6 +224,22 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
private List<ContextualCard> getCardsToKeep(List<ContextualCard> cards) {
|
||||
if (mSavedCards != null) {
|
||||
//screen rotate
|
||||
final List<ContextualCard> cardsToKeep = cards.stream()
|
||||
.filter(card -> mSavedCards.contains(card.getName()))
|
||||
.collect(Collectors.toList());
|
||||
mSavedCards = null;
|
||||
return cardsToKeep;
|
||||
} else {
|
||||
//navigate back to the homepage or after dismissing a card
|
||||
return cards.stream()
|
||||
.filter(card -> mContextualCards.contains(card))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
static class CardContentLoaderCallbacks implements
|
||||
LoaderManager.LoaderCallbacks<List<ContextualCard>> {
|
||||
|
||||
|
||||
@@ -42,7 +42,8 @@ public class ContextualCardsFragment extends InstrumentedFragment {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mContextualCardManager = new ContextualCardManager(getContext(), getSettingsLifecycle());
|
||||
mContextualCardManager = new ContextualCardManager(getContext(), getSettingsLifecycle(),
|
||||
savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,18 +1,38 @@
|
||||
package com.android.settings.location;
|
||||
|
||||
import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
|
||||
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
|
||||
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.LocationManager;
|
||||
import android.permission.RuntimePermissionPresenter;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class AppLocationPermissionPreferenceController extends
|
||||
AbstractPreferenceController implements PreferenceControllerMixin {
|
||||
LocationBasePreferenceController implements PreferenceControllerMixin {
|
||||
|
||||
private static final String KEY_APP_LEVEL_PERMISSIONS = "app_level_permissions";
|
||||
/** Total number of apps that has location permission. */
|
||||
private int mNumTotal = -1;
|
||||
/** Total number of apps that has background location permission. */
|
||||
private int mNumBackground = -1;
|
||||
private final LocationManager mLocationManager;
|
||||
private Preference mPreference;
|
||||
|
||||
public AppLocationPermissionPreferenceController(Context context) {
|
||||
super(context);
|
||||
public AppLocationPermissionPreferenceController(Context context, Lifecycle lifecycle) {
|
||||
super(context, lifecycle);
|
||||
mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -25,4 +45,53 @@ public class AppLocationPermissionPreferenceController extends
|
||||
return Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED, 1) == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
if (mLocationManager.isLocationEnabled()) {
|
||||
if (mNumTotal == -1 || mNumBackground == -1) {
|
||||
return mContext.getString(R.string.location_settings_loading_app_permission_stats);
|
||||
}
|
||||
return mContext.getResources().getQuantityString(
|
||||
R.plurals.location_app_permission_summary_location_on, mNumBackground,
|
||||
mNumBackground, mNumTotal);
|
||||
} else {
|
||||
return mContext.getString(R.string.location_app_permission_summary_location_off);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
mPreference = preference;
|
||||
final AtomicInteger loadingInProgress = new AtomicInteger(2);
|
||||
refreshSummary(preference);
|
||||
// Bail out if location has been disabled.
|
||||
if (!mLocationManager.isLocationEnabled()) {
|
||||
return;
|
||||
}
|
||||
RuntimePermissionPresenter.getInstance(mContext).countPermissionApps(
|
||||
Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION), false, false,
|
||||
(numApps) -> {
|
||||
mNumTotal = numApps;
|
||||
if (loadingInProgress.decrementAndGet() == 0) {
|
||||
refreshSummary(preference);
|
||||
}
|
||||
}, null);
|
||||
|
||||
RuntimePermissionPresenter.getInstance(mContext).countPermissionApps(
|
||||
Collections.singletonList(ACCESS_BACKGROUND_LOCATION), true, false,
|
||||
(numApps) -> {
|
||||
mNumBackground = numApps;
|
||||
if (loadingInProgress.decrementAndGet() == 0) {
|
||||
refreshSummary(preference);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationModeChanged(int mode, boolean restricted) {
|
||||
// 'null' is checked inside updateState(), so no need to check here.
|
||||
updateState(mPreference);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,15 +35,15 @@ import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnPause;
|
||||
import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
|
||||
|
||||
/**
|
||||
* A class that listens to location settings change and modifies location settings
|
||||
* settings.
|
||||
*/
|
||||
public class LocationEnabler implements LifecycleObserver, OnResume, OnPause {
|
||||
public class LocationEnabler implements LifecycleObserver, OnStart, OnStop {
|
||||
|
||||
private static final String TAG = "LocationEnabler";
|
||||
@VisibleForTesting
|
||||
@@ -73,7 +73,7 @@ public class LocationEnabler implements LifecycleObserver, OnResume, OnPause {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
public void onStart() {
|
||||
if (mReceiver == null) {
|
||||
mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
@@ -90,12 +90,8 @@ public class LocationEnabler implements LifecycleObserver, OnResume, OnPause {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
try {
|
||||
mContext.unregisterReceiver(mReceiver);
|
||||
} catch (RuntimeException e) {
|
||||
// Ignore exceptions caused by race condition
|
||||
}
|
||||
public void onStop() {
|
||||
mContext.unregisterReceiver(mReceiver);
|
||||
}
|
||||
|
||||
void refreshLocationMode() {
|
||||
|
||||
@@ -35,7 +35,7 @@ import com.android.settings.search.Indexable;
|
||||
import com.android.settings.widget.SwitchBar;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.location.RecentLocationApps;
|
||||
import com.android.settingslib.location.RecentLocationAccesses;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -52,7 +52,7 @@ import java.util.List;
|
||||
* <li>In switch bar: location master switch. Used to toggle location on and off.
|
||||
* </li>
|
||||
* </ul>
|
||||
* <li>Recent location requests: automatically populated by {@link RecentLocationApps}</li>
|
||||
* <li>Recent location requests: automatically populated by {@link RecentLocationAccesses}</li>
|
||||
* <li>Location services: multi-app settings provided from outside the Android framework. Each
|
||||
* is injected by a system-partition app via the {@link SettingInjectorService} API.</li>
|
||||
* </ul>
|
||||
@@ -122,13 +122,11 @@ public class LocationSettings extends DashboardFragment {
|
||||
private static List<AbstractPreferenceController> buildPreferenceControllers(
|
||||
Context context, LocationSettings fragment, Lifecycle lifecycle) {
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
controllers.add(new AppLocationPermissionPreferenceController(context));
|
||||
controllers.add(new AppLocationPermissionPreferenceController(context, lifecycle));
|
||||
controllers.add(new LocationForWorkPreferenceController(context, lifecycle));
|
||||
controllers.add(
|
||||
new RecentLocationRequestPreferenceController(context, fragment, lifecycle));
|
||||
controllers.add(new RecentLocationAccessPreferenceController(context));
|
||||
controllers.add(new LocationScanningPreferenceController(context));
|
||||
controllers.add(
|
||||
new LocationServicePreferenceController(context, fragment, lifecycle));
|
||||
controllers.add(new LocationServicePreferenceController(context, fragment, lifecycle));
|
||||
controllers.add(new LocationFooterPreferenceController(context, lifecycle));
|
||||
return controllers;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.location;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.location.RecentLocationAccesses;
|
||||
import com.android.settingslib.widget.AppEntitiesHeaderController;
|
||||
import com.android.settingslib.widget.LayoutPreference;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RecentLocationAccessPreferenceController extends AbstractPreferenceController
|
||||
implements PreferenceControllerMixin {
|
||||
/** Key for the recent location apps dashboard */
|
||||
private static final String KEY_APPS_DASHBOARD = "apps_dashboard";
|
||||
private final RecentLocationAccesses mRecentLocationAccesses;
|
||||
private AppEntitiesHeaderController mController;
|
||||
private static final int MAXIMUM_APP_COUNT = 3;
|
||||
|
||||
public RecentLocationAccessPreferenceController(Context context) {
|
||||
this(context, new RecentLocationAccesses(context));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
RecentLocationAccessPreferenceController(Context context,
|
||||
RecentLocationAccesses recentAccesses) {
|
||||
super(context);
|
||||
mRecentLocationAccesses = recentAccesses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return KEY_APPS_DASHBOARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
final LayoutPreference preference = (LayoutPreference) screen.findPreference(
|
||||
KEY_APPS_DASHBOARD);
|
||||
final View view = preference.findViewById(R.id.app_entities_header);
|
||||
mController = AppEntitiesHeaderController.newInstance(mContext, view)
|
||||
.setHeaderTitleRes(R.string.location_category_recent_location_access)
|
||||
.setHeaderDetailsRes(R.string.location_recent_location_access_view_details)
|
||||
.setHeaderDetailsClickListener((View v) -> {
|
||||
final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
|
||||
intent.putExtra(Intent.EXTRA_PERMISSION_NAME,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
mContext.startActivity(intent);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
updateRecentApps();
|
||||
}
|
||||
|
||||
private void updateRecentApps() {
|
||||
final List<RecentLocationAccesses.Access> recentLocationAccesses =
|
||||
mRecentLocationAccesses.getAppListSorted();
|
||||
if (recentLocationAccesses.size() > 0) {
|
||||
// Display the top 3 preferences to container in original order.
|
||||
int i = 0;
|
||||
for (; i < Math.min(recentLocationAccesses.size(), MAXIMUM_APP_COUNT); i++) {
|
||||
final RecentLocationAccesses.Access access = recentLocationAccesses.get(i);
|
||||
mController.setAppEntity(i, access.icon, access.label, access.contentDescription);
|
||||
}
|
||||
for (; i < MAXIMUM_APP_COUNT; i++) {
|
||||
mController.removeAppEntity(i);
|
||||
}
|
||||
} else {
|
||||
// If there's no item to display, add a "No recent apps" item.
|
||||
}
|
||||
mController.apply();
|
||||
}
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.location;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.location.RecentLocationApps;
|
||||
import com.android.settingslib.widget.apppreference.AppPreference;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RecentLocationRequestPreferenceController extends LocationBasePreferenceController {
|
||||
|
||||
/** Key for preference category "Recent location requests" */
|
||||
private static final String KEY_RECENT_LOCATION_REQUESTS = "recent_location_requests";
|
||||
@VisibleForTesting
|
||||
static final String KEY_SEE_ALL_BUTTON = "recent_location_requests_see_all_button";
|
||||
private final LocationSettings mFragment;
|
||||
private final RecentLocationApps mRecentLocationApps;
|
||||
private PreferenceCategory mCategoryRecentLocationRequests;
|
||||
private Preference mSeeAllButton;
|
||||
|
||||
/** Used in this class and {@link RecentLocationRequestSeeAllPreferenceController} */
|
||||
static class PackageEntryClickedListener implements Preference.OnPreferenceClickListener {
|
||||
private final DashboardFragment mFragment;
|
||||
private final String mPackage;
|
||||
private final UserHandle mUserHandle;
|
||||
|
||||
public PackageEntryClickedListener(DashboardFragment fragment, String packageName,
|
||||
UserHandle userHandle) {
|
||||
mFragment = fragment;
|
||||
mPackage = packageName;
|
||||
mUserHandle = userHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
// start new fragment to display extended information
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(AppInfoDashboardFragment.ARG_PACKAGE_NAME, mPackage);
|
||||
|
||||
new SubSettingLauncher(mFragment.getContext())
|
||||
.setDestination(AppInfoDashboardFragment.class.getName())
|
||||
.setArguments(args)
|
||||
.setTitleRes(R.string.application_info_label)
|
||||
.setUserHandle(mUserHandle)
|
||||
.setSourceMetricsCategory(mFragment.getMetricsCategory())
|
||||
.launch();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public RecentLocationRequestPreferenceController(Context context, LocationSettings fragment,
|
||||
Lifecycle lifecycle) {
|
||||
this(context, fragment, lifecycle, new RecentLocationApps(context));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
RecentLocationRequestPreferenceController(Context context, LocationSettings fragment,
|
||||
Lifecycle lifecycle, RecentLocationApps recentApps) {
|
||||
super(context, lifecycle);
|
||||
mFragment = fragment;
|
||||
mRecentLocationApps = recentApps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return KEY_RECENT_LOCATION_REQUESTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mCategoryRecentLocationRequests =
|
||||
(PreferenceCategory) screen.findPreference(KEY_RECENT_LOCATION_REQUESTS);
|
||||
mSeeAllButton = screen.findPreference(KEY_SEE_ALL_BUTTON);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
mCategoryRecentLocationRequests.removeAll();
|
||||
mSeeAllButton.setVisible(false);
|
||||
|
||||
final Context prefContext = preference.getContext();
|
||||
final List<RecentLocationApps.Request> recentLocationRequests =
|
||||
mRecentLocationApps.getAppListSorted();
|
||||
|
||||
if (recentLocationRequests.size() > 3) {
|
||||
// Display the top 3 preferences to container in original order.
|
||||
for (int i = 0; i < 3; i++) {
|
||||
mCategoryRecentLocationRequests.addPreference(
|
||||
createAppPreference(prefContext, recentLocationRequests.get(i)));
|
||||
}
|
||||
// Display a button to list all requests
|
||||
mSeeAllButton.setVisible(true);
|
||||
} else if (recentLocationRequests.size() > 0) {
|
||||
// Add preferences to container in original order (already sorted by recency).
|
||||
for (RecentLocationApps.Request request : recentLocationRequests) {
|
||||
mCategoryRecentLocationRequests.addPreference(
|
||||
createAppPreference(prefContext, request));
|
||||
}
|
||||
} else {
|
||||
// If there's no item to display, add a "No recent apps" item.
|
||||
final Preference banner = createAppPreference(prefContext);
|
||||
banner.setTitle(R.string.location_no_recent_apps);
|
||||
banner.setSelectable(false);
|
||||
mCategoryRecentLocationRequests.addPreference(banner);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationModeChanged(int mode, boolean restricted) {
|
||||
mCategoryRecentLocationRequests.setEnabled(mLocationEnabler.isEnabled(mode));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
AppPreference createAppPreference(Context prefContext) {
|
||||
return new AppPreference(prefContext);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
AppPreference createAppPreference(Context prefContext, RecentLocationApps.Request request) {
|
||||
final AppPreference pref = createAppPreference(prefContext);
|
||||
pref.setSummary(request.contentDescription);
|
||||
pref.setIcon(request.icon);
|
||||
pref.setTitle(request.label);
|
||||
pref.setOnPreferenceClickListener(new PackageEntryClickedListener(
|
||||
mFragment, request.packageName, request.userHandle));
|
||||
return pref;
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 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.location;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.search.Indexable;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/** Dashboard Fragment to display all recent location requests, sorted by recency. */
|
||||
@SearchIndexable
|
||||
public class RecentLocationRequestSeeAllFragment extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "RecentLocationReqAll";
|
||||
|
||||
public static final String PATH =
|
||||
"com.android.settings.location.RecentLocationRequestSeeAllFragment";
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return MetricsEvent.RECENT_LOCATION_REQUESTS_ALL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.location_recent_requests_see_all;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
|
||||
return buildPreferenceControllers(context, getSettingsLifecycle(), this);
|
||||
}
|
||||
|
||||
private static List<AbstractPreferenceController> buildPreferenceControllers(
|
||||
Context context, Lifecycle lifecycle, RecentLocationRequestSeeAllFragment fragment) {
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
controllers.add(
|
||||
new RecentLocationRequestSeeAllPreferenceController(context, lifecycle, fragment));
|
||||
return controllers;
|
||||
}
|
||||
|
||||
/**
|
||||
* For Search.
|
||||
*/
|
||||
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider() {
|
||||
@Override
|
||||
public List<SearchIndexableResource> getXmlResourcesToIndex(
|
||||
Context context, boolean enabled) {
|
||||
final SearchIndexableResource sir = new SearchIndexableResource(context);
|
||||
sir.xmlResId = R.xml.location_recent_requests_see_all;
|
||||
return Arrays.asList(sir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AbstractPreferenceController> getPreferenceControllers(Context
|
||||
context) {
|
||||
return buildPreferenceControllers(
|
||||
context, /* lifecycle = */ null, /* fragment = */ null);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 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.location;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.location.RecentLocationApps;
|
||||
import com.android.settingslib.widget.apppreference.AppPreference;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Preference controller for preference category displaying all recent location requests. */
|
||||
public class RecentLocationRequestSeeAllPreferenceController
|
||||
extends LocationBasePreferenceController {
|
||||
|
||||
/** Key for preference category "All recent location requests" */
|
||||
private static final String KEY_ALL_RECENT_LOCATION_REQUESTS = "all_recent_location_requests";
|
||||
private final RecentLocationRequestSeeAllFragment mFragment;
|
||||
private PreferenceCategory mCategoryAllRecentLocationRequests;
|
||||
private RecentLocationApps mRecentLocationApps;
|
||||
|
||||
public RecentLocationRequestSeeAllPreferenceController(
|
||||
Context context, Lifecycle lifecycle, RecentLocationRequestSeeAllFragment fragment) {
|
||||
this(context, lifecycle, fragment, new RecentLocationApps(context));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
RecentLocationRequestSeeAllPreferenceController(
|
||||
Context context,
|
||||
Lifecycle lifecycle,
|
||||
RecentLocationRequestSeeAllFragment fragment,
|
||||
RecentLocationApps recentLocationApps) {
|
||||
super(context, lifecycle);
|
||||
mFragment = fragment;
|
||||
mRecentLocationApps = recentLocationApps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return KEY_ALL_RECENT_LOCATION_REQUESTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationModeChanged(int mode, boolean restricted) {
|
||||
mCategoryAllRecentLocationRequests.setEnabled(mLocationEnabler.isEnabled(mode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mCategoryAllRecentLocationRequests =
|
||||
(PreferenceCategory) screen.findPreference(KEY_ALL_RECENT_LOCATION_REQUESTS);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
mCategoryAllRecentLocationRequests.removeAll();
|
||||
List<RecentLocationApps.Request> requests = mRecentLocationApps.getAppListSorted();
|
||||
for (RecentLocationApps.Request request : requests) {
|
||||
Preference appPreference = createAppPreference(preference.getContext(), request);
|
||||
mCategoryAllRecentLocationRequests.addPreference(appPreference);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
AppPreference createAppPreference(
|
||||
Context prefContext, RecentLocationApps.Request request) {
|
||||
final AppPreference pref = new AppPreference(prefContext);
|
||||
pref.setSummary(request.contentDescription);
|
||||
pref.setIcon(request.icon);
|
||||
pref.setTitle(request.label);
|
||||
pref.setOnPreferenceClickListener(
|
||||
new RecentLocationRequestPreferenceController.PackageEntryClickedListener(
|
||||
mFragment, request.packageName, request.userHandle));
|
||||
return pref;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.android.settings.location;
|
||||
|
||||
import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
|
||||
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
|
||||
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.location.LocationManager;
|
||||
import android.permission.RuntimePermissionPresenter;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
public class TopLevelLocationPreferenceController extends BasePreferenceController implements
|
||||
LifecycleObserver, OnStart, OnStop {
|
||||
private static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED =
|
||||
new IntentFilter(LocationManager.MODE_CHANGED_ACTION);
|
||||
private final LocationManager mLocationManager;
|
||||
/** Total number of apps that has location permission. */
|
||||
private int mNumTotal = -1;
|
||||
private BroadcastReceiver mReceiver;
|
||||
private Preference mPreference;
|
||||
|
||||
public TopLevelLocationPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
if (mLocationManager.isLocationEnabled()) {
|
||||
if (mNumTotal == -1) {
|
||||
return mContext.getString(R.string.location_settings_loading_app_permission_stats);
|
||||
}
|
||||
return mContext.getResources().getQuantityString(
|
||||
R.plurals.location_settings_summary_location_on,
|
||||
mNumTotal, mNumTotal);
|
||||
} else {
|
||||
return mContext.getString(R.string.location_settings_summary_location_off);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
mPreference = preference;
|
||||
refreshSummary(preference);
|
||||
// Bail out if location has been disabled.
|
||||
if (!mLocationManager.isLocationEnabled()) {
|
||||
return;
|
||||
}
|
||||
RuntimePermissionPresenter.getInstance(mContext).countPermissionApps(
|
||||
Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION), false, false,
|
||||
(numApps) -> {
|
||||
mNumTotal = numApps;
|
||||
refreshSummary(preference);
|
||||
}, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
if (mReceiver == null) {
|
||||
mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
refreshLocationMode();
|
||||
}
|
||||
};
|
||||
}
|
||||
mContext.registerReceiver(mReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED);
|
||||
refreshLocationMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
mContext.unregisterReceiver(mReceiver);
|
||||
}
|
||||
|
||||
private void refreshLocationMode() {
|
||||
// 'null' is checked inside updateState(), so no need to check here.
|
||||
updateState(mPreference);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,9 @@ package com.android.settings.network;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.wifi.WifiConnectionPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
@@ -29,9 +31,11 @@ import androidx.preference.PreferenceScreen;
|
||||
// are two or more active mobile subscriptions. It shows an overview of available network
|
||||
// connections with an entry for wifi (if connected) and an entry for each subscription.
|
||||
public class MultiNetworkHeaderController extends BasePreferenceController implements
|
||||
WifiConnectionPreferenceController.UpdateListener,
|
||||
SubscriptionsPreferenceController.UpdateListener {
|
||||
public static final String TAG = "MultiNetworkHdrCtrl";
|
||||
|
||||
private WifiConnectionPreferenceController mWifiController;
|
||||
private SubscriptionsPreferenceController mSubscriptionsController;
|
||||
private PreferenceCategory mPreferenceCategory;
|
||||
|
||||
@@ -40,13 +44,22 @@ public class MultiNetworkHeaderController extends BasePreferenceController imple
|
||||
}
|
||||
|
||||
public void init(Lifecycle lifecycle) {
|
||||
mWifiController = createWifiController(lifecycle);
|
||||
mSubscriptionsController = createSubscriptionsController(lifecycle);
|
||||
// TODO(asargent) - add in a controller for showing wifi status here
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
WifiConnectionPreferenceController createWifiController(Lifecycle lifecycle) {
|
||||
final int prefOrder = 0;
|
||||
return new WifiConnectionPreferenceController(mContext, lifecycle, this, mPreferenceKey,
|
||||
prefOrder, MetricsProto.MetricsEvent.SETTINGS_NETWORK_CATEGORY);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
SubscriptionsPreferenceController createSubscriptionsController(Lifecycle lifecycle) {
|
||||
return new SubscriptionsPreferenceController(mContext, lifecycle, this, mPreferenceKey, 10);
|
||||
final int prefStartOrder = 10;
|
||||
return new SubscriptionsPreferenceController(mContext, lifecycle, this, mPreferenceKey,
|
||||
prefStartOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,6 +67,7 @@ public class MultiNetworkHeaderController extends BasePreferenceController imple
|
||||
super.displayPreference(screen);
|
||||
mPreferenceCategory = (PreferenceCategory) screen.findPreference(mPreferenceKey);
|
||||
mPreferenceCategory.setVisible(isAvailable());
|
||||
mWifiController.displayPreference(screen);
|
||||
mSubscriptionsController.displayPreference(screen);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.android.settings.R;
|
||||
import com.android.settings.accounts.AccountFeatureProvider;
|
||||
import com.android.settings.applications.ApplicationFeatureProvider;
|
||||
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;
|
||||
import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider;
|
||||
@@ -114,6 +115,8 @@ public abstract class FeatureFactory {
|
||||
|
||||
public abstract FaceFeatureProvider getFaceFeatureProvider();
|
||||
|
||||
public abstract BluetoothFeatureProvider getBluetoothFeatureProvider(Context context);
|
||||
|
||||
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.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;
|
||||
import com.android.settings.core.instrumentation.SettingsMetricsFeatureProvider;
|
||||
import com.android.settings.dashboard.DashboardFeatureProvider;
|
||||
@@ -81,6 +83,7 @@ public class FeatureFactoryImpl extends FeatureFactory {
|
||||
private PanelFeatureProvider mPanelFeatureProvider;
|
||||
private ContextualCardFeatureProvider mContextualCardFeatureProvider;
|
||||
private FaceFeatureProvider mFaceFeatureProvider;
|
||||
private BluetoothFeatureProvider mBluetoothFeatureProvider;
|
||||
|
||||
@Override
|
||||
public SupportFeatureProvider getSupportFeatureProvider(Context context) {
|
||||
@@ -242,4 +245,13 @@ public class FeatureFactoryImpl extends FeatureFactory {
|
||||
}
|
||||
return mFaceFeatureProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BluetoothFeatureProvider getBluetoothFeatureProvider(Context context) {
|
||||
if (mBluetoothFeatureProvider == null) {
|
||||
mBluetoothFeatureProvider = new BluetoothFeatureProviderImpl(
|
||||
context.getApplicationContext());
|
||||
}
|
||||
return mBluetoothFeatureProvider;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,8 +135,9 @@ public class SetupChooseLockPassword extends ChooseLockPassword {
|
||||
@Override
|
||||
protected void updateUi() {
|
||||
super.updateUi();
|
||||
mSkipButton.setVisibility(mForFingerprint ? View.GONE : View.VISIBLE);
|
||||
|
||||
// Show the skip button during SUW but not during Settings > Biometric Enrollment
|
||||
mSkipButton.setVisibility(View.VISIBLE);
|
||||
if (mOptionsButton != null) {
|
||||
mOptionsButton.setVisibility(
|
||||
mUiStage == Stage.Introduction ? View.VISIBLE : View.GONE);
|
||||
|
||||
@@ -70,17 +70,15 @@ public class SetupChooseLockPattern extends ChooseLockPattern {
|
||||
ChooseLockTypeDialogFragment.newInstance(mUserId)
|
||||
.show(getChildFragmentManager(), null));
|
||||
}
|
||||
// enable skip button only during setup wizard and not with fingerprint flow.
|
||||
if (!mForFingerprint) {
|
||||
Button skipButton = view.findViewById(R.id.skip_button);
|
||||
skipButton.setVisibility(View.VISIBLE);
|
||||
skipButton.setOnClickListener(v -> {
|
||||
SetupSkipDialog dialog = SetupSkipDialog.newInstance(
|
||||
getActivity().getIntent()
|
||||
.getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false));
|
||||
dialog.show(getFragmentManager());
|
||||
// Show the skip button during SUW but not during Settings > Biometric Enrollment
|
||||
Button skipButton = view.findViewById(R.id.skip_button);
|
||||
skipButton.setVisibility(View.VISIBLE);
|
||||
skipButton.setOnClickListener(v -> {
|
||||
SetupSkipDialog dialog = SetupSkipDialog.newInstance(
|
||||
getActivity().getIntent()
|
||||
.getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false));
|
||||
dialog.show(getFragmentManager());
|
||||
});
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
48
src/com/android/settings/slices/SlicePreference.java
Normal file
48
src/com/android/settings/slices/SlicePreference.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.slices;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.widget.SliceView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.widget.LayoutPreference;
|
||||
|
||||
/**
|
||||
* Preference for {@link SliceView}
|
||||
*/
|
||||
public class SlicePreference extends LayoutPreference {
|
||||
private SliceView mSliceView;
|
||||
|
||||
public SlicePreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs, R.attr.slicePreferenceStyle);
|
||||
mSliceView = findViewById(R.id.slice_view);
|
||||
}
|
||||
|
||||
public SlicePreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, R.attr.slicePreferenceStyle);
|
||||
mSliceView = findViewById(R.id.slice_view);
|
||||
}
|
||||
|
||||
public void onSliceUpdated(Slice slice) {
|
||||
mSliceView.onChanged(slice);
|
||||
notifyChanged();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.slices;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.widget.SliceLiveData;
|
||||
import androidx.slice.widget.SliceView;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
|
||||
/**
|
||||
* Default {@link BasePreferenceController} for {@link SliceView}. It will take {@link Uri} for
|
||||
* Slice and display what's inside this {@link Uri}
|
||||
*/
|
||||
public class SlicePreferenceController extends BasePreferenceController implements
|
||||
LifecycleObserver, OnStart, OnStop, Observer<Slice> {
|
||||
@VisibleForTesting
|
||||
LiveData<Slice> mLiveData;
|
||||
private SlicePreference mSlicePreference;
|
||||
private Uri mUri;
|
||||
|
||||
public SlicePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
|
||||
mSlicePreference = (SlicePreference) screen.findPreference(
|
||||
getPreferenceKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return mUri != null ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||
}
|
||||
|
||||
public void setSliceUri(Uri uri) {
|
||||
mUri = uri;
|
||||
mLiveData = SliceLiveData.fromUri(mContext, mUri);
|
||||
|
||||
//TODO(b/120803703): figure out why we need to remove observer first
|
||||
mLiveData.removeObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
if (mLiveData != null) {
|
||||
mLiveData.observeForever(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
if (mLiveData != null) {
|
||||
mLiveData.removeObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(Slice slice) {
|
||||
mSlicePreference.onSliceUpdated(slice);
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import android.os.Message;
|
||||
import android.widget.BaseAdapter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.internal.PreferenceImageView;
|
||||
|
||||
@@ -46,7 +47,10 @@ import com.android.settings.R;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settings.wifi.NetworkRequestErrorDialogFragment.ERROR_DIALOG_TYPE;
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.wifi.AccessPoint;
|
||||
import com.android.settingslib.wifi.WifiTracker;
|
||||
import com.android.settingslib.wifi.WifiTrackerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -62,10 +66,14 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
|
||||
/** Message sent to us to stop scanning wifi and pop up timeout dialog. */
|
||||
private static final int MESSAGE_STOP_SCAN_WIFI_LIST = 0;
|
||||
|
||||
/** Spec defines there should be 5 wifi ap on the list at most. */
|
||||
private static final int MAX_NUMBER_LIST_ITEM = 5;
|
||||
|
||||
/** Delayed time to stop scanning wifi. */
|
||||
private static final int DELAY_TIME_STOP_SCAN_MS = 30 * 1000;
|
||||
|
||||
private List<AccessPoint> mAccessPointList;
|
||||
private FilterWifiTracker mFilterWifiTracker;
|
||||
private AccessPointAdapter mDialogAdapter;
|
||||
private NetworkRequestUserSelectionCallback mUserSelectionCallback;
|
||||
|
||||
@@ -159,6 +167,19 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
|
||||
if (wifiManager != null) {
|
||||
wifiManager.unregisterNetworkRequestMatchCallback(this);
|
||||
}
|
||||
|
||||
if (mFilterWifiTracker != null) {
|
||||
mFilterWifiTracker.onPause();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mFilterWifiTracker != null) {
|
||||
mFilterWifiTracker.onDestroy();
|
||||
mFilterWifiTracker = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -172,6 +193,11 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
|
||||
}
|
||||
// Sets time-out to stop scanning.
|
||||
mHandler.sendEmptyMessageDelayed(MESSAGE_STOP_SCAN_WIFI_LIST, DELAY_TIME_STOP_SCAN_MS);
|
||||
|
||||
if (mFilterWifiTracker == null) {
|
||||
mFilterWifiTracker = new FilterWifiTracker(getActivity(), getSettingsLifecycle());
|
||||
}
|
||||
mFilterWifiTracker.onResume();
|
||||
}
|
||||
|
||||
private final Handler mHandler = new Handler() {
|
||||
@@ -268,17 +294,33 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
|
||||
|
||||
@Override
|
||||
public void onMatch(List<ScanResult> scanResults) {
|
||||
// TODO(b/119846365): Checks if we could escalate the converting effort.
|
||||
// Converts ScanResult to WifiConfiguration.
|
||||
List<WifiConfiguration> wifiConfigurations = null;
|
||||
final WifiManager wifiManager = getContext().getApplicationContext()
|
||||
.getSystemService(WifiManager.class);
|
||||
if (wifiManager != null) {
|
||||
wifiConfigurations = wifiManager.getAllMatchingWifiConfigs(scanResults);
|
||||
mHandler.removeMessages(MESSAGE_STOP_SCAN_WIFI_LIST);
|
||||
renewAccessPointList(scanResults);
|
||||
|
||||
notifyAdapterRefresh();
|
||||
}
|
||||
|
||||
// Updates internal AccessPoint list from WifiTracker. scanResults are used to update key list
|
||||
// of AccessPoint, and could be null if there is no necessary to update key list.
|
||||
private void renewAccessPointList(List<ScanResult> scanResults) {
|
||||
if (mFilterWifiTracker == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
setUpAccessPointList(wifiConfigurations);
|
||||
// TODO(b/119846365): Checks if we could escalate the converting effort.
|
||||
// Updates keys of scanResults into FilterWifiTracker for updating matched AccessPoints.
|
||||
if (scanResults != null) {
|
||||
mFilterWifiTracker.updateKeys(scanResults);
|
||||
}
|
||||
|
||||
// Re-gets matched AccessPoints from WifiTracker.
|
||||
final List<AccessPoint> list = getAccessPointList();
|
||||
list.clear();
|
||||
list.addAll(mFilterWifiTracker.getAccessPoints());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void notifyAdapterRefresh() {
|
||||
if (getDialogAdapter() != null) {
|
||||
getDialogAdapter().notifyDataSetChanged();
|
||||
}
|
||||
@@ -286,48 +328,99 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
|
||||
|
||||
@Override
|
||||
public void onUserSelectionConnectSuccess(WifiConfiguration wificonfiguration) {
|
||||
if (getDialogAdapter() != null) {
|
||||
updateAccessPointListItem(wificonfiguration);
|
||||
getDialogAdapter().notifyDataSetChanged();
|
||||
}
|
||||
// Dismisses current dialog, since connection is success.
|
||||
dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserSelectionConnectFailure(WifiConfiguration wificonfiguration) {
|
||||
if (mDialogAdapter != null) {
|
||||
updateAccessPointListItem(wificonfiguration);
|
||||
getDialogAdapter().notifyDataSetChanged();
|
||||
}
|
||||
stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE.ABORT);
|
||||
}
|
||||
|
||||
private void updateAccessPointListItem(WifiConfiguration wificonfiguration) {
|
||||
if (wificonfiguration == null) {
|
||||
return;
|
||||
private final class FilterWifiTracker {
|
||||
private final List<String> mAccessPointKeys;
|
||||
private final WifiTracker mWifiTracker;
|
||||
|
||||
public FilterWifiTracker(Context context, Lifecycle lifecycle) {
|
||||
mWifiTracker = WifiTrackerFactory.create(context, mWifiListener,
|
||||
lifecycle, /* includeSaved */ true, /* includeScans */ true);
|
||||
mAccessPointKeys = new ArrayList<>();
|
||||
}
|
||||
|
||||
final List<AccessPoint> accessPointList = getAccessPointList();
|
||||
final int accessPointListSize = accessPointList.size();
|
||||
/**
|
||||
* Updates key list from input. {@code onMatch()} may be called in multi-times according
|
||||
* wifi scanning result, so needs patchwork here.
|
||||
*/
|
||||
public void updateKeys(List<ScanResult> scanResults) {
|
||||
for (ScanResult scanResult : scanResults) {
|
||||
final String key = AccessPoint.getKey(scanResult);
|
||||
if (!mAccessPointKeys.contains(key)) {
|
||||
mAccessPointKeys.add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < accessPointListSize; i++) {
|
||||
AccessPoint accessPoint = accessPointList.get(i);
|
||||
// It is the same AccessPoint SSID, and should be replaced to update latest properties.
|
||||
if (accessPoint.matches(wificonfiguration)) {
|
||||
accessPointList.set(i, new AccessPoint(getContext(), wificonfiguration));
|
||||
break;
|
||||
/**
|
||||
* Returns only AccessPoints whose key is in {@code mAccessPointKeys}.
|
||||
*
|
||||
* @return List of matched AccessPoints.
|
||||
*/
|
||||
public List<AccessPoint> getAccessPoints() {
|
||||
final List<AccessPoint> allAccessPoints = mWifiTracker.getAccessPoints();
|
||||
final List<AccessPoint> result = new ArrayList<>();
|
||||
|
||||
// The order should be kept, because order means wifi score (sorting in WifiTracker).
|
||||
int count = 0;
|
||||
for (AccessPoint accessPoint : allAccessPoints) {
|
||||
final String key = accessPoint.getKey();
|
||||
if (mAccessPointKeys.contains(key)) {
|
||||
result.add(accessPoint);
|
||||
|
||||
count++;
|
||||
// Limits how many count of items could show.
|
||||
if (count >= MAX_NUMBER_LIST_ITEM) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private WifiTracker.WifiListener mWifiListener = new WifiTracker.WifiListener() {
|
||||
|
||||
@Override
|
||||
public void onWifiStateChanged(int state) {
|
||||
notifyAdapterRefresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectedChanged() {
|
||||
notifyAdapterRefresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccessPointsChanged() {
|
||||
notifyAdapterRefresh();
|
||||
}
|
||||
};
|
||||
|
||||
public void onDestroy() {
|
||||
if (mWifiTracker != null) {
|
||||
mWifiTracker.onDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
if (mWifiTracker != null) {
|
||||
mWifiTracker.onStart();
|
||||
}
|
||||
}
|
||||
|
||||
public void onPause() {
|
||||
if (mWifiTracker != null) {
|
||||
mWifiTracker.onStop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpAccessPointList(List<WifiConfiguration> wifiConfigurations) {
|
||||
// Grants for zero size input, since maybe current wifi is off or somethings are wrong.
|
||||
if (wifiConfigurations == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<AccessPoint> accessPointList = getAccessPointList();
|
||||
accessPointList.clear();
|
||||
for (WifiConfiguration config : wifiConfigurations) {
|
||||
accessPointList.add(new AccessPoint(getContext(), config));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.wifi;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.wifi.details.WifiNetworkDetailsFragment;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.wifi.AccessPoint;
|
||||
import com.android.settingslib.wifi.AccessPointPreference;
|
||||
import com.android.settingslib.wifi.WifiTracker;
|
||||
import com.android.settingslib.wifi.WifiTrackerFactory;
|
||||
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
/**
|
||||
* This places a preference into a PreferenceGroup owned by some parent
|
||||
* controller class when there is a wifi connection present.
|
||||
*/
|
||||
public class WifiConnectionPreferenceController extends AbstractPreferenceController implements
|
||||
WifiTracker.WifiListener {
|
||||
|
||||
private static final String TAG = "WifiConnPrefCtrl";
|
||||
|
||||
private static final String KEY = "active_wifi_connection";
|
||||
|
||||
private UpdateListener mUpdateListener;
|
||||
private Context mPrefContext;
|
||||
private String mPreferenceGroupKey;
|
||||
private PreferenceGroup mPreferenceGroup;
|
||||
private WifiTracker mWifiTracker;
|
||||
private AccessPointPreference mPreference;
|
||||
private AccessPointPreference.UserBadgeCache mBadgeCache;
|
||||
private int order;
|
||||
private int mMetricsCategory;
|
||||
|
||||
/**
|
||||
* Used to notify a parent controller that this controller has changed in availability, or has
|
||||
* updated the content in the preference that it manages.
|
||||
*/
|
||||
public interface UpdateListener {
|
||||
void onChildrenUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context the context for the UI where we're placing the preference
|
||||
* @param lifecycle for listening to lifecycle events for the UI
|
||||
* @param updateListener for notifying a parent controller of changes
|
||||
* @param preferenceGroupKey the key to use to lookup the PreferenceGroup where this controller
|
||||
* will add its preference
|
||||
* @param order the order that the preference added by this controller should use -
|
||||
* useful when this preference needs to be ordered in a specific way
|
||||
* relative to others in the PreferenceGroup
|
||||
* @param metricsCategory - the category to use as the source when handling the click on the
|
||||
* pref to go to the wifi connection detail page
|
||||
*/
|
||||
public WifiConnectionPreferenceController(Context context, Lifecycle lifecycle,
|
||||
UpdateListener updateListener, String preferenceGroupKey, int order,
|
||||
int metricsCategory) {
|
||||
super(context);
|
||||
mUpdateListener = updateListener;
|
||||
mPreferenceGroupKey = preferenceGroupKey;
|
||||
mWifiTracker = WifiTrackerFactory.create(context, this, lifecycle, true /* includeSaved */,
|
||||
true /* includeScans */);
|
||||
this.order = order;
|
||||
mMetricsCategory = metricsCategory;
|
||||
mBadgeCache = new AccessPointPreference.UserBadgeCache(context.getPackageManager());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return mWifiTracker.isConnected() && getCurrentAccessPoint() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mPreferenceGroup = (PreferenceGroup) screen.findPreference(mPreferenceGroupKey);
|
||||
mPrefContext = screen.getContext();
|
||||
update();
|
||||
}
|
||||
|
||||
private AccessPoint getCurrentAccessPoint() {
|
||||
for (AccessPoint accessPoint : mWifiTracker.getAccessPoints()) {
|
||||
if (accessPoint.isActive()) {
|
||||
return accessPoint;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void updatePreference(AccessPoint accessPoint) {
|
||||
if (mPreference != null) {
|
||||
mPreferenceGroup.removePreference(mPreference);
|
||||
mPreference = null;
|
||||
}
|
||||
if (accessPoint == null) {
|
||||
return;
|
||||
}
|
||||
if (mPrefContext != null) {
|
||||
mPreference = new AccessPointPreference(accessPoint, mPrefContext, mBadgeCache,
|
||||
R.drawable.ic_wifi_signal_0, false /* forSavedNetworks */);
|
||||
mPreference.setKey(KEY);
|
||||
mPreference.refresh();
|
||||
mPreference.setOrder(order);
|
||||
|
||||
mPreference.setOnPreferenceClickListener(pref -> {
|
||||
Bundle args = new Bundle();
|
||||
mPreference.getAccessPoint().saveWifiState(args);
|
||||
new SubSettingLauncher(mPrefContext)
|
||||
.setTitleRes(R.string.pref_title_network_details)
|
||||
.setDestination(WifiNetworkDetailsFragment.class.getName())
|
||||
.setArguments(args)
|
||||
.setSourceMetricsCategory(mMetricsCategory)
|
||||
.launch();
|
||||
return true;
|
||||
});
|
||||
mPreferenceGroup.addPreference(mPreference);
|
||||
}
|
||||
}
|
||||
|
||||
private void update() {
|
||||
AccessPoint connectedAccessPoint = null;
|
||||
if (mWifiTracker.isConnected()) {
|
||||
connectedAccessPoint = getCurrentAccessPoint();
|
||||
}
|
||||
if (connectedAccessPoint == null) {
|
||||
updatePreference(null);
|
||||
} else {
|
||||
if (mPreference == null || !mPreference.getAccessPoint().equals(connectedAccessPoint)) {
|
||||
updatePreference(connectedAccessPoint);
|
||||
} else if (mPreference != null) {
|
||||
mPreference.refresh();
|
||||
}
|
||||
}
|
||||
mUpdateListener.onChildrenUpdated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWifiStateChanged(int state) {
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectedChanged() {
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccessPointsChanged() {
|
||||
update();
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package com.android.settings.wifi.dpp;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
|
||||
/**
|
||||
@@ -30,6 +31,11 @@ public class WifiDppAddDeviceFragment extends WifiDppQrCodeBaseFragment {
|
||||
return R.layout.wifi_dpp_add_device_fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated (Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.settings.wifi.dpp;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
|
||||
/**
|
||||
@@ -30,6 +31,11 @@ public class WifiDppChooseSavedWifiNetworkFragment extends WifiDppQrCodeBaseFrag
|
||||
return R.layout.wifi_dpp_choose_saved_wifi_network_fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated (Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
@@ -27,7 +27,6 @@ import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
|
||||
import com.android.settings.core.InstrumentedActivity;
|
||||
import com.android.settings.R;
|
||||
|
||||
@@ -67,8 +66,7 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
//TODO:Should we use a new metrics category for Wi-Fi DPP?
|
||||
return MetricsProto.MetricsEvent.WIFI_NETWORK_DETAILS;
|
||||
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,7 +27,6 @@ import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
|
||||
import com.android.settings.core.InstrumentedActivity;
|
||||
import com.android.settings.R;
|
||||
|
||||
@@ -47,8 +46,7 @@ public class WifiDppEnrolleeActivity extends InstrumentedActivity {
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
//TODO:Should we use a new metrics category for Wi-Fi DPP?
|
||||
return MetricsProto.MetricsEvent.WIFI_NETWORK_DETAILS;
|
||||
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_ENROLLEE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,8 +26,6 @@ import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
|
||||
import com.android.settings.core.InstrumentedFragment;
|
||||
import com.android.settings.R;
|
||||
|
||||
@@ -45,6 +43,7 @@ import com.android.settings.R;
|
||||
* {@code WifiDppAddDeviceFragment}
|
||||
*/
|
||||
public abstract class WifiDppQrCodeBaseFragment extends InstrumentedFragment {
|
||||
private ImageView mHeaderIcon;
|
||||
private TextView mTitle;
|
||||
private TextView mDescription;
|
||||
|
||||
@@ -61,12 +60,6 @@ public abstract class WifiDppQrCodeBaseFragment extends InstrumentedFragment {
|
||||
|
||||
abstract protected int getLayout();
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
//TODO:Should we use a new metrics category for Wi-Fi DPP?
|
||||
return MetricsProto.MetricsEvent.WIFI_NETWORK_DETAILS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -81,6 +74,7 @@ public abstract class WifiDppQrCodeBaseFragment extends InstrumentedFragment {
|
||||
}
|
||||
|
||||
private void initView(View view) {
|
||||
mHeaderIcon = view.findViewById(R.id.header_icon);
|
||||
mTitle = view.findViewById(R.id.title);
|
||||
mDescription = view.findViewById(R.id.description);
|
||||
mErrorMessage = view.findViewById(R.id.error_message);
|
||||
@@ -95,6 +89,10 @@ public abstract class WifiDppQrCodeBaseFragment extends InstrumentedFragment {
|
||||
mButtonRight = view.findViewById(R.id.button_right);
|
||||
}
|
||||
|
||||
protected void setHeaderIconImageResource(int resId) {
|
||||
mHeaderIcon.setImageResource(resId);
|
||||
}
|
||||
|
||||
protected void setTitle(String title) {
|
||||
mTitle.setText(title);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
|
||||
/**
|
||||
@@ -35,6 +36,11 @@ public class WifiDppQrCodeGeneratorFragment extends WifiDppQrCodeBaseFragment {
|
||||
return R.layout.wifi_dpp_qrcode_generator_fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
|
||||
}
|
||||
|
||||
// Container Activity must implement this interface
|
||||
public interface OnQrCodeGeneratorFragmentAddButtonClickedListener {
|
||||
public void onQrCodeGeneratorFragmentAddButtonClicked();
|
||||
@@ -45,6 +51,7 @@ public class WifiDppQrCodeGeneratorFragment extends WifiDppQrCodeBaseFragment {
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
setHeaderIconImageResource(R.drawable.ic_qrcode_24dp);
|
||||
WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity())
|
||||
.getWifiNetworkConfig();
|
||||
if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
|
||||
@@ -79,7 +86,7 @@ public class WifiDppQrCodeGeneratorFragment extends WifiDppQrCodeBaseFragment {
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
MenuItem item = menu.add(0, Menu.FIRST, 0, R.string.next_label);
|
||||
item.setIcon(R.drawable.ic_menu_add);
|
||||
item.setIcon(R.drawable.ic_scan_24dp);
|
||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.view.TextureView;
|
||||
import android.view.TextureView.SurfaceTextureListener;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.wifi.qrcode.QrCamera;
|
||||
import com.android.settings.wifi.qrcode.QrDecorateView;
|
||||
@@ -55,6 +56,15 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
|
||||
return R.layout.wifi_dpp_qrcode_scanner_fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
if (mConfiguratorMode) {
|
||||
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
|
||||
} else {
|
||||
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_ENROLLEE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configurator container activity of the fragment should create instance with this constructor.
|
||||
*/
|
||||
@@ -79,6 +89,8 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
setHeaderIconImageResource(R.drawable.ic_scan_24dp);
|
||||
|
||||
if (mConfiguratorMode) {
|
||||
setTitle(getString(R.string.wifi_dpp_add_device_to_network));
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ import android.widget.ScrollView;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.android.settings.testutils.shadow.ShadowUtils;
|
||||
import com.google.android.setupcompat.item.FooterButton;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -386,7 +387,7 @@ public class MasterClearTest {
|
||||
public void testOnGlobalLayout_shouldNotRemoveListener() {
|
||||
final ViewTreeObserver viewTreeObserver = mock(ViewTreeObserver.class);
|
||||
mMasterClear.mScrollView = mScrollView;
|
||||
mMasterClear.mInitiateButton = mock(Button.class);
|
||||
mMasterClear.mInitiateButton = mock(FooterButton.class);
|
||||
doReturn(true).when(mMasterClear).hasReachedBottom(any());
|
||||
when(mScrollView.getViewTreeObserver()).thenReturn(viewTreeObserver);
|
||||
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.android.settings.applications.specialaccess.financialapps;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import static android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS;
|
||||
import static android.Manifest.permission.READ_SMS;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
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.shadow.api.Shadow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class FinancialAppsControllerTest {
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
private AppOpsManager mAppOpsManager;
|
||||
@Mock
|
||||
private PreferenceScreen mRoot;
|
||||
@Mock
|
||||
private Preference mPreference;
|
||||
|
||||
private Context mContext;
|
||||
private PackageInfo mPackageInfoNoPermissionRequested;
|
||||
private PackageInfo mPackageInfoPermissionRequestedQPlus;
|
||||
private PackageInfo mPackageInfoPermissionRequestedPreQ;
|
||||
private FinancialAppsController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
||||
when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOpsManager);
|
||||
|
||||
initializePackageInfos();
|
||||
|
||||
mController = new FinancialAppsController(mContext, "key");
|
||||
mController.displayPreference(mRoot);
|
||||
}
|
||||
|
||||
private void initializePackageInfos() {
|
||||
mPackageInfoNoPermissionRequested = new PackageInfo();
|
||||
mPackageInfoNoPermissionRequested.applicationInfo = new ApplicationInfo();
|
||||
|
||||
mPackageInfoPermissionRequestedQPlus = new PackageInfo();
|
||||
mPackageInfoPermissionRequestedQPlus.applicationInfo = new ApplicationInfo();
|
||||
// TODO(b/121161546): update after robolectric test support Q
|
||||
//mPackageInfoPermissionRequestedQPlus.applicationInfo.targetSdkVersion =
|
||||
// Build.VERSION_CODES.Q;
|
||||
mPackageInfoPermissionRequestedQPlus.applicationInfo.uid = 2001;
|
||||
mPackageInfoPermissionRequestedQPlus.applicationInfo.nonLocalizedLabel = "QPLUS Package";
|
||||
mPackageInfoPermissionRequestedQPlus.packageName = "QPLUS";
|
||||
mPackageInfoPermissionRequestedQPlus.requestedPermissions =
|
||||
new String[] {SMS_FINANCIAL_TRANSACTIONS};
|
||||
|
||||
mPackageInfoPermissionRequestedPreQ = new PackageInfo();
|
||||
mPackageInfoPermissionRequestedPreQ.applicationInfo = new ApplicationInfo();
|
||||
mPackageInfoPermissionRequestedPreQ.applicationInfo.targetSdkVersion = Build.VERSION_CODES.M;
|
||||
mPackageInfoPermissionRequestedPreQ.applicationInfo.uid = 2002;
|
||||
mPackageInfoPermissionRequestedPreQ.applicationInfo.nonLocalizedLabel = "PREQ Package";
|
||||
mPackageInfoPermissionRequestedPreQ.packageName = "PREQ";
|
||||
mPackageInfoPermissionRequestedPreQ.requestedPermissions = new String[] {READ_SMS};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_true() {
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noPreferenceAddedWhenNoPackageRequestPermission() {
|
||||
when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS))
|
||||
.thenReturn(new ArrayList<PackageInfo>(
|
||||
Arrays.asList(mPackageInfoNoPermissionRequested)));
|
||||
mController.updateState(null);
|
||||
assertThat(mController.mRoot.getPreferenceCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
//TODO(b/121161546): Add these tests after robolectric test support Q
|
||||
/*
|
||||
@Test
|
||||
public void preferenceAddedWhenPreQPackageRequestPermission() {
|
||||
when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS))
|
||||
.thenReturn(new ArrayList<PackageInfo>(
|
||||
Arrays.asList(mPackageInfoPermissionRequestedPreQ)));
|
||||
mController.updateState(null);
|
||||
assertThat(mController.mRoot.getPreferenceCount()).isEqualTo(1);
|
||||
SwitchPreference pref = (SwitchPreference) mController.mRoot.getPreference(0);
|
||||
assertThat(pref).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preferenceAddedWhenQPlusPackageRequestPermission() {
|
||||
when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS))
|
||||
.thenReturn(new ArrayList<PackageInfo>(
|
||||
Arrays.asList(mPackageInfoPermissionRequestedQPlus)));
|
||||
mController.updateState(null);
|
||||
assertThat(mController.mRoot.getPreferenceCount()).isEqualTo(1);
|
||||
SwitchPreference pref = (SwitchPreference) mController.mRoot.getPreference(0);
|
||||
assertThat(pref).isNotNull();
|
||||
}*/
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.bluetooth;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class BluetoothFeatureProviderImplTest {
|
||||
private static final String PARAMETER_KEY = "addr";
|
||||
private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
|
||||
private BluetoothFeatureProvider mBluetoothFeatureProvider;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mBluetoothFeatureProvider = new BluetoothFeatureProviderImpl(
|
||||
RuntimeEnvironment.application);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBluetoothDeviceSettingsUri_containCorrectMacAddress() {
|
||||
final Uri uri = mBluetoothFeatureProvider.getBluetoothDeviceSettingsUri(MAC_ADDRESS);
|
||||
assertThat(uri.getQueryParameterNames()).containsExactly(PARAMETER_KEY);
|
||||
assertThat(uri.getQueryParameter(PARAMETER_KEY)).isEqualTo(MAC_ADDRESS);
|
||||
}
|
||||
}
|
||||
@@ -42,13 +42,16 @@ import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class ContextualCardManagerTest {
|
||||
|
||||
private static final String TEST_SLICE_URI = "context://test/test";
|
||||
private static final String TEST_SLICE_NAME = "test_name";
|
||||
|
||||
@Mock
|
||||
ContextualCardUpdateListener mListener;
|
||||
@@ -61,7 +64,8 @@ public class ContextualCardManagerTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
final ContextualCardsFragment fragment = new ContextualCardsFragment();
|
||||
mManager = new ContextualCardManager(mContext, fragment.getSettingsLifecycle());
|
||||
mManager = new ContextualCardManager(mContext, fragment.getSettingsLifecycle(),
|
||||
null /* bundle */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -135,9 +139,74 @@ public class ContextualCardManagerTest {
|
||||
verify(manager, never()).onContextualCardUpdated(anyMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onFinishCardLoading_newLaunch_twoLoadedCards_shouldShowTwoCards() {
|
||||
mManager.mStartTime = System.currentTimeMillis();
|
||||
mManager.setListener(mListener);
|
||||
final List<ContextualCard> cards = new ArrayList<>();
|
||||
cards.add(buildContextualCard(TEST_SLICE_URI));
|
||||
cards.add(buildContextualCard(TEST_SLICE_URI));
|
||||
|
||||
mManager.onFinishCardLoading(cards);
|
||||
|
||||
assertThat(mManager.mContextualCards).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onFinishCardLoading_hasSavedCard_shouldOnlyShowSavedCard() {
|
||||
mManager.setListener(mListener);
|
||||
final List<String> savedCardNames = new ArrayList<>();
|
||||
savedCardNames.add(TEST_SLICE_NAME);
|
||||
mManager.mIsFirstLaunch = false;
|
||||
mManager.mSavedCards = savedCardNames;
|
||||
final ContextualCard newCard =
|
||||
new ContextualCard.Builder()
|
||||
.setName("test_name2")
|
||||
.setCardType(ContextualCard.CardType.SLICE)
|
||||
.setSliceUri(Uri.parse("content://test/test2"))
|
||||
.build();
|
||||
final List<ContextualCard> loadedCards = new ArrayList<>();
|
||||
loadedCards.add(buildContextualCard(TEST_SLICE_URI));
|
||||
loadedCards.add(newCard);
|
||||
|
||||
mManager.onFinishCardLoading(loadedCards);
|
||||
|
||||
final List<String> actualCards = mManager.mContextualCards.stream()
|
||||
.map(ContextualCard::getName)
|
||||
.collect(Collectors.toList());
|
||||
final List<String> expectedCards = Arrays.asList(TEST_SLICE_NAME);
|
||||
assertThat(actualCards).containsExactlyElementsIn(expectedCards);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onFinishCardLoading_reloadData_shouldOnlyShowOldCard() {
|
||||
mManager.setListener(mListener);
|
||||
mManager.mIsFirstLaunch = false;
|
||||
//old card
|
||||
mManager.mContextualCards.add(buildContextualCard(TEST_SLICE_URI));
|
||||
final ContextualCard newCard =
|
||||
new ContextualCard.Builder()
|
||||
.setName("test_name2")
|
||||
.setCardType(ContextualCard.CardType.SLICE)
|
||||
.setSliceUri(Uri.parse("content://test/test2"))
|
||||
.build();
|
||||
final List<ContextualCard> loadedCards = new ArrayList<>();
|
||||
loadedCards.add(buildContextualCard(TEST_SLICE_URI));
|
||||
loadedCards.add(newCard);
|
||||
|
||||
mManager.onFinishCardLoading(loadedCards);
|
||||
|
||||
final List<String> actualCards = mManager.mContextualCards.stream()
|
||||
.map(ContextualCard::getName)
|
||||
.collect(Collectors.toList());
|
||||
final List<String> expectedCards = Arrays.asList(TEST_SLICE_NAME);
|
||||
assertThat(actualCards).containsExactlyElementsIn(expectedCards);
|
||||
}
|
||||
|
||||
private ContextualCard buildContextualCard(String sliceUri) {
|
||||
return new ContextualCard.Builder()
|
||||
.setName("test_name")
|
||||
.setName(TEST_SLICE_NAME)
|
||||
.setCardType(ContextualCard.CardType.SLICE)
|
||||
.setSliceUri(Uri.parse(sliceUri))
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -21,11 +25,16 @@ public class AppLocationPermissionPreferenceControllerTest {
|
||||
@Mock
|
||||
private Context mContext;
|
||||
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private Lifecycle mLifecycle;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mController = new AppLocationPermissionPreferenceController(mContext);
|
||||
mLifecycleOwner = () -> mLifecycle;
|
||||
mLifecycle = new Lifecycle(mLifecycleOwner);
|
||||
mController = new AppLocationPermissionPreferenceController(mContext, mLifecycle);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -84,30 +84,31 @@ public class LocationEnablerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onResume_shouldSetActiveAndRegisterListener() {
|
||||
mEnabler.onResume();
|
||||
public void onStart_shouldSetActiveAndRegisterListener() {
|
||||
mEnabler.onStart();
|
||||
|
||||
verify(mContext).registerReceiver(eq(mEnabler.mReceiver),
|
||||
eq(LocationEnabler.INTENT_FILTER_LOCATION_MODE_CHANGED));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onResume_shouldRefreshLocationMode() {
|
||||
mEnabler.onResume();
|
||||
public void onStart_shouldRefreshLocationMode() {
|
||||
mEnabler.onStart();
|
||||
|
||||
verify(mEnabler).refreshLocationMode();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPause_shouldUnregisterListener() {
|
||||
mEnabler.onPause();
|
||||
public void onStop_shouldUnregisterListener() {
|
||||
mEnabler.onStart();
|
||||
mEnabler.onStop();
|
||||
|
||||
verify(mContext).unregisterReceiver(mEnabler.mReceiver);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onReceive_shouldRefreshLocationMode() {
|
||||
mEnabler.onResume();
|
||||
mEnabler.onStart();
|
||||
reset(mListener);
|
||||
mEnabler.mReceiver.onReceive(mContext, new Intent());
|
||||
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.location;
|
||||
|
||||
import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
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.Intent;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.location.RecentLocationApps;
|
||||
import com.android.settingslib.location.RecentLocationApps.Request;
|
||||
import com.android.settingslib.widget.apppreference.AppPreference;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class RecentLocationRequestPreferenceControllerTest {
|
||||
|
||||
@Mock
|
||||
private LocationSettings mFragment;
|
||||
@Mock
|
||||
private PreferenceCategory mCategory;
|
||||
@Mock
|
||||
private PreferenceScreen mScreen;
|
||||
@Mock
|
||||
private RecentLocationApps mRecentLocationApps;
|
||||
@Mock
|
||||
private Preference mSeeAllButton;
|
||||
|
||||
private Context mContext;
|
||||
private RecentLocationRequestPreferenceController mController;
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private Lifecycle mLifecycle;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mLifecycleOwner = () -> mLifecycle;
|
||||
mLifecycle = new Lifecycle(mLifecycleOwner);
|
||||
mController = spy(new RecentLocationRequestPreferenceController(
|
||||
mContext, mFragment, mLifecycle, mRecentLocationApps));
|
||||
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mCategory);
|
||||
when(mScreen.findPreference(mController.KEY_SEE_ALL_BUTTON)).thenReturn(mSeeAllButton);
|
||||
final String key = mController.getPreferenceKey();
|
||||
when(mCategory.getKey()).thenReturn(key);
|
||||
when(mCategory.getContext()).thenReturn(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLocationModeChanged_LocationOn_shouldEnablePreference() {
|
||||
mController.displayPreference(mScreen);
|
||||
|
||||
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
|
||||
|
||||
verify(mCategory).setEnabled(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLocationModeChanged_LocationOff_shouldDisablePreference() {
|
||||
mController.displayPreference(mScreen);
|
||||
|
||||
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_OFF, false);
|
||||
|
||||
verify(mCategory).setEnabled(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_noRecentRequest_shouldRemoveAllAndAddBanner() {
|
||||
doReturn(new ArrayList<>()).when(mRecentLocationApps).getAppListSorted();
|
||||
mController.displayPreference(mScreen);
|
||||
|
||||
mController.updateState(mCategory);
|
||||
|
||||
verify(mCategory).removeAll();
|
||||
final String title = mContext.getString(R.string.location_no_recent_apps);
|
||||
verify(mCategory).addPreference(argThat(titleMatches(title)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_hasRecentRequest_shouldRemoveAllAndAddInjectedSettings() {
|
||||
List<Request> requests = createMockRequests(2);
|
||||
doReturn(requests).when(mRecentLocationApps).getAppListSorted();
|
||||
|
||||
mController.displayPreference(mScreen);
|
||||
mController.updateState(mCategory);
|
||||
|
||||
verify(mCategory).removeAll();
|
||||
// Verifies two preferences are added in original order
|
||||
InOrder inOrder = Mockito.inOrder(mCategory);
|
||||
inOrder.verify(mCategory).addPreference(argThat(titleMatches("appTitle0")));
|
||||
inOrder.verify(mCategory).addPreference(argThat(titleMatches("appTitle1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_hasOverThreeRequests_shouldDisplaySeeAllButton() {
|
||||
List<Request> requests = createMockRequests(6);
|
||||
when(mRecentLocationApps.getAppListSorted()).thenReturn(requests);
|
||||
|
||||
mController.displayPreference(mScreen);
|
||||
mController.updateState(mCategory);
|
||||
|
||||
verify(mCategory).removeAll();
|
||||
// Verifies the first three preferences are added
|
||||
InOrder inOrder = Mockito.inOrder(mCategory);
|
||||
inOrder.verify(mCategory).addPreference(argThat(titleMatches("appTitle0")));
|
||||
inOrder.verify(mCategory).addPreference(argThat(titleMatches("appTitle1")));
|
||||
inOrder.verify(mCategory).addPreference(argThat(titleMatches("appTitle2")));
|
||||
verify(mCategory, never()).addPreference(argThat(titleMatches("appTitle3")));
|
||||
// Verifies the "See all" preference is visible
|
||||
verify(mSeeAllButton).setVisible(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createAppPreference_shouldAddClickListener() {
|
||||
final Request request = mock(Request.class);
|
||||
final AppPreference preference = mock(AppPreference.class);
|
||||
doReturn(preference).when(mController).createAppPreference(any(Context.class));
|
||||
|
||||
mController.createAppPreference(mContext, request);
|
||||
|
||||
verify(preference).setOnPreferenceClickListener(
|
||||
any(RecentLocationRequestPreferenceController.PackageEntryClickedListener.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceClick_shouldLaunchAppDetails() {
|
||||
final Context context = mock(Context.class);
|
||||
when(mFragment.getContext()).thenReturn(context);
|
||||
|
||||
final List<RecentLocationApps.Request> requests = new ArrayList<>();
|
||||
final Request request = mock(Request.class);
|
||||
requests.add(request);
|
||||
doReturn(requests).when(mRecentLocationApps).getAppListSorted();
|
||||
final AppPreference preference = new AppPreference(mContext);
|
||||
doReturn(preference).when(mController).createAppPreference(any(Context.class));
|
||||
mController.displayPreference(mScreen);
|
||||
mController.updateState(mCategory);
|
||||
|
||||
final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
|
||||
|
||||
preference.performClick();
|
||||
|
||||
verify(context).startActivity(intent.capture());
|
||||
|
||||
assertThat(intent.getValue().getStringExtra(EXTRA_SHOW_FRAGMENT))
|
||||
.isEqualTo(AppInfoDashboardFragment.class.getName());
|
||||
}
|
||||
|
||||
private static ArgumentMatcher<Preference> titleMatches(String expected) {
|
||||
return preference -> TextUtils.equals(expected, preference.getTitle());
|
||||
}
|
||||
|
||||
private List<RecentLocationApps.Request> createMockRequests(int count) {
|
||||
List<RecentLocationApps.Request> requests = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
// Add mock requests
|
||||
Request req = mock(Request.class, "request" + i);
|
||||
requests.add(req);
|
||||
// Map mock AppPreferences with mock requests
|
||||
String title = "appTitle" + i;
|
||||
AppPreference appPreference = mock(AppPreference.class, "AppPreference" + i);
|
||||
doReturn(title).when(appPreference).getTitle();
|
||||
doReturn(appPreference)
|
||||
.when(mController).createAppPreference(any(Context.class), eq(req));
|
||||
}
|
||||
return requests;
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 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.location;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
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.content.Context;
|
||||
import android.provider.Settings.Secure;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.location.RecentLocationApps;
|
||||
import com.android.settingslib.location.RecentLocationApps.Request;
|
||||
import com.android.settingslib.widget.apppreference.AppPreference;
|
||||
|
||||
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 java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
/** Unit tests for {@link RecentLocationRequestSeeAllPreferenceController} */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class RecentLocationRequestSeeAllPreferenceControllerTest {
|
||||
|
||||
@Mock
|
||||
RecentLocationRequestSeeAllFragment mFragment;
|
||||
@Mock
|
||||
private PreferenceScreen mScreen;
|
||||
@Mock
|
||||
private PreferenceCategory mCategory;
|
||||
@Mock
|
||||
private RecentLocationApps mRecentLocationApps;
|
||||
|
||||
private Context mContext;
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private Lifecycle mLifecycle;
|
||||
private RecentLocationRequestSeeAllPreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mLifecycleOwner = () -> mLifecycle;
|
||||
mLifecycle = new Lifecycle(mLifecycleOwner);
|
||||
mController = spy(
|
||||
new RecentLocationRequestSeeAllPreferenceController(
|
||||
mContext, mLifecycle, mFragment, mRecentLocationApps));
|
||||
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mCategory);
|
||||
final String key = mController.getPreferenceKey();
|
||||
when(mCategory.getKey()).thenReturn(key);
|
||||
when(mCategory.getContext()).thenReturn(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLocationModeChanged_locationOn_shouldEnablePreference() {
|
||||
mController.displayPreference(mScreen);
|
||||
|
||||
mController.onLocationModeChanged(Secure.LOCATION_MODE_HIGH_ACCURACY, false);
|
||||
|
||||
verify(mCategory).setEnabled(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLocationModeChanged_locationOff_shouldDisablePreference() {
|
||||
mController.displayPreference(mScreen);
|
||||
|
||||
mController.onLocationModeChanged(Secure.LOCATION_MODE_OFF, false);
|
||||
|
||||
verify(mCategory).setEnabled(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_shouldRemoveAll() {
|
||||
doReturn(Collections.EMPTY_LIST).when(mRecentLocationApps).getAppListSorted();
|
||||
|
||||
mController.displayPreference(mScreen);
|
||||
mController.updateState(mCategory);
|
||||
|
||||
verify(mCategory).removeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_hasRecentLocationRequest_shouldAddPreference() {
|
||||
Request request = mock(Request.class);
|
||||
AppPreference appPreference = mock(AppPreference.class);
|
||||
doReturn(appPreference)
|
||||
.when(mController).createAppPreference(any(Context.class), eq(request));
|
||||
when(mRecentLocationApps.getAppListSorted())
|
||||
.thenReturn(new ArrayList<>(Collections.singletonList(request)));
|
||||
|
||||
mController.displayPreference(mScreen);
|
||||
mController.updateState(mCategory);
|
||||
|
||||
verify(mCategory).removeAll();
|
||||
verify(mCategory).addPreference(appPreference);
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import static org.mockito.Mockito.when;
|
||||
import android.content.Context;
|
||||
import android.telephony.SubscriptionManager;
|
||||
|
||||
import com.android.settings.wifi.WifiConnectionPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -55,6 +56,8 @@ public class MultiNetworkHeaderControllerTest {
|
||||
@Mock
|
||||
private PreferenceCategory mPreferenceCategory;
|
||||
@Mock
|
||||
private WifiConnectionPreferenceController mWifiController;
|
||||
@Mock
|
||||
private SubscriptionsPreferenceController mSubscriptionsController;
|
||||
@Mock
|
||||
private SubscriptionManager mSubscriptionManager;
|
||||
@@ -74,6 +77,7 @@ public class MultiNetworkHeaderControllerTest {
|
||||
when(mPreferenceScreen.findPreference(eq(KEY_HEADER))).thenReturn(mPreferenceCategory);
|
||||
|
||||
mHeaderController = spy(new MultiNetworkHeaderController(mContext, KEY_HEADER));
|
||||
doReturn(mWifiController).when(mHeaderController).createWifiController(mLifecycle);
|
||||
doReturn(mSubscriptionsController).when(mHeaderController).createSubscriptionsController(
|
||||
mLifecycle);
|
||||
}
|
||||
@@ -85,8 +89,9 @@ public class MultiNetworkHeaderControllerTest {
|
||||
|
||||
// When calling displayPreference, the header itself should only be visible if the
|
||||
// subscriptions controller says it is available. This is a helper for test cases of this logic.
|
||||
private void displayPreferenceTest(boolean subscriptionsAvailable,
|
||||
private void displayPreferenceTest(boolean wifiAvailable, boolean subscriptionsAvailable,
|
||||
boolean setVisibleExpectedValue) {
|
||||
when(mWifiController.isAvailable()).thenReturn(wifiAvailable);
|
||||
when(mSubscriptionsController.isAvailable()).thenReturn(subscriptionsAvailable);
|
||||
|
||||
mHeaderController.init(mLifecycle);
|
||||
@@ -96,13 +101,23 @@ public class MultiNetworkHeaderControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayPreference_subscriptionsNotAvailable_categoryIsNotVisible() {
|
||||
displayPreferenceTest(false, false);
|
||||
public void displayPreference_bothNotAvailable_categoryIsNotVisible() {
|
||||
displayPreferenceTest(false, false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayPreference_subscriptionsAvailable_categoryIsVisible() {
|
||||
displayPreferenceTest(true, true);
|
||||
public void displayPreference_wifiAvailableButNotSubscriptions_categoryIsNotVisible() {
|
||||
displayPreferenceTest(true, false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayPreference_subscriptionsAvailableButNotWifi_categoryIsVisible() {
|
||||
displayPreferenceTest(false, true, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayPreference_bothAvailable_categoryIsVisible() {
|
||||
displayPreferenceTest(true, true, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.network;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.wifi.WifiConnectionPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.wifi.AccessPoint;
|
||||
import com.android.settingslib.wifi.AccessPointPreference;
|
||||
import com.android.settingslib.wifi.WifiTracker;
|
||||
import com.android.settingslib.wifi.WifiTrackerFactory;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class WifiConnectionPreferenceControllerTest {
|
||||
private static final String KEY = "wifi_connection";
|
||||
|
||||
@Mock
|
||||
WifiTracker mWifiTracker;
|
||||
@Mock
|
||||
PreferenceScreen mScreen;
|
||||
@Mock
|
||||
PreferenceCategory mPreferenceCategory;
|
||||
|
||||
private Context mContext;
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
private Lifecycle mLifecycle;
|
||||
private WifiConnectionPreferenceController mController;
|
||||
private int mOnChildUpdatedCount;
|
||||
private WifiConnectionPreferenceController.UpdateListener mUpdateListener;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
WifiTrackerFactory.setTestingWifiTracker(mWifiTracker);
|
||||
mLifecycleOwner = () -> mLifecycle;
|
||||
mLifecycle = new Lifecycle(mLifecycleOwner);
|
||||
when(mScreen.findPreference(eq(KEY))).thenReturn(mPreferenceCategory);
|
||||
when(mScreen.getContext()).thenReturn(mContext);
|
||||
mUpdateListener = () -> mOnChildUpdatedCount++;
|
||||
|
||||
mController = new WifiConnectionPreferenceController(mContext, mLifecycle, mUpdateListener,
|
||||
KEY, 0, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_noWiFiConnection_availableIsFalse() {
|
||||
when(mWifiTracker.isConnected()).thenReturn(false);
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayPreference_noWiFiConnection_noPreferenceAdded() {
|
||||
when(mWifiTracker.isConnected()).thenReturn(false);
|
||||
when(mWifiTracker.getAccessPoints()).thenReturn(new ArrayList<>());
|
||||
mController.displayPreference(mScreen);
|
||||
verify(mPreferenceCategory, never()).addPreference(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayPreference_hasWiFiConnection_preferenceAdded() {
|
||||
when(mWifiTracker.isConnected()).thenReturn(true);
|
||||
final AccessPoint accessPoint = mock(AccessPoint.class);
|
||||
when(accessPoint.isActive()).thenReturn(true);
|
||||
when(mWifiTracker.getAccessPoints()).thenReturn(Arrays.asList(accessPoint));
|
||||
mController.displayPreference(mScreen);
|
||||
verify(mPreferenceCategory).addPreference(any(AccessPointPreference.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onConnectedChanged_wifiBecameDisconnected_preferenceRemoved() {
|
||||
when(mWifiTracker.isConnected()).thenReturn(true);
|
||||
final AccessPoint accessPoint = mock(AccessPoint.class);
|
||||
|
||||
when(accessPoint.isActive()).thenReturn(true);
|
||||
when(mWifiTracker.getAccessPoints()).thenReturn(Arrays.asList(accessPoint));
|
||||
mController.displayPreference(mScreen);
|
||||
final ArgumentCaptor<AccessPointPreference> captor = ArgumentCaptor.forClass(
|
||||
AccessPointPreference.class);
|
||||
verify(mPreferenceCategory).addPreference(captor.capture());
|
||||
final AccessPointPreference pref = captor.getValue();
|
||||
|
||||
when(mWifiTracker.isConnected()).thenReturn(false);
|
||||
when(mWifiTracker.getAccessPoints()).thenReturn(new ArrayList<>());
|
||||
final int onUpdatedCountBefore = mOnChildUpdatedCount;
|
||||
mController.onConnectedChanged();
|
||||
verify(mPreferenceCategory).removePreference(pref);
|
||||
assertThat(mOnChildUpdatedCount).isEqualTo(onUpdatedCountBefore + 1);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void onAccessPointsChanged_wifiBecameConnectedToDifferentAP_preferenceReplaced() {
|
||||
when(mWifiTracker.isConnected()).thenReturn(true);
|
||||
final AccessPoint accessPoint1 = mock(AccessPoint.class);
|
||||
|
||||
when(accessPoint1.isActive()).thenReturn(true);
|
||||
when(mWifiTracker.getAccessPoints()).thenReturn(Arrays.asList(accessPoint1));
|
||||
mController.displayPreference(mScreen);
|
||||
final ArgumentCaptor<AccessPointPreference> captor = ArgumentCaptor.forClass(
|
||||
AccessPointPreference.class);
|
||||
|
||||
|
||||
final AccessPoint accessPoint2 = mock(AccessPoint.class);
|
||||
when(accessPoint1.isActive()).thenReturn(false);
|
||||
when(accessPoint2.isActive()).thenReturn(true);
|
||||
when(mWifiTracker.getAccessPoints()).thenReturn(Arrays.asList(accessPoint1, accessPoint2));
|
||||
final int onUpdatedCountBefore = mOnChildUpdatedCount;
|
||||
mController.onAccessPointsChanged();
|
||||
|
||||
verify(mPreferenceCategory, times(2)).addPreference(captor.capture());
|
||||
final AccessPointPreference pref1 = captor.getAllValues().get(0);
|
||||
final AccessPointPreference pref2 = captor.getAllValues().get(1);
|
||||
assertThat(pref1.getAccessPoint()).isEqualTo(accessPoint1);
|
||||
assertThat(pref2.getAccessPoint()).isEqualTo(accessPoint2);
|
||||
verify(mPreferenceCategory).removePreference(eq(pref1));
|
||||
assertThat(mOnChildUpdatedCount).isEqualTo(onUpdatedCountBefore + 1);
|
||||
}
|
||||
}
|
||||
@@ -164,23 +164,6 @@ public class SetupChooseLockPatternTest {
|
||||
assertThat(findFragment(mActivity).mChosenPattern).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipButton_shouldNotBeVisible_duringFingerprintFlow() {
|
||||
final Intent intent =
|
||||
SetupChooseLockPattern.modifyIntentForSetup(
|
||||
application,
|
||||
new IntentBuilder(application)
|
||||
.setUserId(UserHandle.myUserId())
|
||||
.setForFingerprint(true)
|
||||
.build());
|
||||
|
||||
mActivity = ActivityController.of(new SetupChooseLockPattern(), intent).setup().get();
|
||||
Button skipButton = mActivity.findViewById(R.id.skip_button);
|
||||
|
||||
assertThat(skipButton).isNotNull();
|
||||
assertThat(skipButton.getVisibility()).isEqualTo(View.GONE);
|
||||
}
|
||||
|
||||
private ChooseLockPatternFragment findFragment(FragmentActivity activity) {
|
||||
return (ChooseLockPatternFragment)
|
||||
activity.getSupportFragmentManager().findFragmentById(R.id.main_content);
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.slices;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.slice.Slice;
|
||||
|
||||
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 SlicePreferenceControllerTest {
|
||||
private static final String KEY = "slice_preference_key";
|
||||
|
||||
@Mock
|
||||
private LiveData<Slice> mLiveData;
|
||||
private Context mContext;
|
||||
private SlicePreferenceController mController;
|
||||
private Uri mUri;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mController = new SlicePreferenceController(mContext, KEY);
|
||||
mController.mLiveData = mLiveData;
|
||||
mUri = Uri.EMPTY;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_uriNull_returnFalse() {
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_uriNotNull_returnTrue() {
|
||||
mController.setSliceUri(mUri);
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStart_registerObserver() {
|
||||
mController.onStart();
|
||||
verify(mLiveData).observeForever(mController);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onStop_unregisterObserver() {
|
||||
mController.onStop();
|
||||
verify(mLiveData).removeObserver(mController);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import android.content.Context;
|
||||
import com.android.settings.accounts.AccountFeatureProvider;
|
||||
import com.android.settings.applications.ApplicationFeatureProvider;
|
||||
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;
|
||||
import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider;
|
||||
@@ -66,6 +67,7 @@ public class FakeFeatureFactory extends FeatureFactory {
|
||||
public final AccountFeatureProvider mAccountFeatureProvider;
|
||||
public final ContextualCardFeatureProvider mContextualCardFeatureProvider;
|
||||
public final FaceFeatureProvider mFaceFeatureProvider;
|
||||
public final BluetoothFeatureProvider mBluetoothFeatureProvider;
|
||||
|
||||
public PanelFeatureProvider panelFeatureProvider;
|
||||
public SlicesFeatureProvider slicesFeatureProvider;
|
||||
@@ -111,6 +113,7 @@ public class FakeFeatureFactory extends FeatureFactory {
|
||||
mContextualCardFeatureProvider = mock(ContextualCardFeatureProvider.class);
|
||||
panelFeatureProvider = mock(PanelFeatureProvider.class);
|
||||
mFaceFeatureProvider = mock(FaceFeatureProvider.class);
|
||||
mBluetoothFeatureProvider = mock(BluetoothFeatureProvider.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -207,4 +210,9 @@ public class FakeFeatureFactory extends FeatureFactory {
|
||||
public FaceFeatureProvider getFaceFeatureProvider() {
|
||||
return mFaceFeatureProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BluetoothFeatureProvider getBluetoothFeatureProvider(Context context) {
|
||||
return mBluetoothFeatureProvider;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,13 @@ package com.android.settings.wifi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
|
||||
import com.android.settingslib.wifi.WifiTracker;
|
||||
import com.android.settingslib.wifi.WifiTrackerFactory;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -34,6 +38,10 @@ public class NetworkRequestDialogActivityTest {
|
||||
|
||||
@Test
|
||||
public void LaunchActivity_shouldShowNetworkRequestDialog() {
|
||||
// Mocks fake WifiTracker, in case of exception in NetworkRequestDialogFragment.onResume().
|
||||
WifiTracker wifiTracker = mock(WifiTracker.class);
|
||||
WifiTrackerFactory.setTestingWifiTracker(wifiTracker);
|
||||
|
||||
Robolectric.setupActivity(NetworkRequestDialogActivity.class);
|
||||
|
||||
AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||
|
||||
@@ -51,6 +51,10 @@ import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import com.android.settingslib.wifi.WifiTracker;
|
||||
import com.android.settingslib.wifi.WifiTrackerFactory;
|
||||
|
||||
import org.robolectric.shadows.ShadowLooper;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@@ -58,16 +62,21 @@ import org.robolectric.shadows.ShadowLooper;
|
||||
public class NetworkRequestDialogFragmentTest {
|
||||
|
||||
private static final String KEY_SSID = "key_ssid";
|
||||
private static final String KEY_SECURITY = "key_security";
|
||||
|
||||
private FragmentActivity mActivity;
|
||||
private NetworkRequestDialogFragment networkRequestDialogFragment;
|
||||
private Context mContext;
|
||||
private WifiTracker mWifiTracker;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mActivity = Robolectric.setupActivity(FragmentActivity.class);
|
||||
networkRequestDialogFragment = spy(NetworkRequestDialogFragment.newInstance());
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
|
||||
mWifiTracker = mock(WifiTracker.class);
|
||||
WifiTrackerFactory.setTestingWifiTracker(mWifiTracker);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -140,71 +149,47 @@ public class NetworkRequestDialogFragmentTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateAccessPointList_onUserSelectionConnectSuccess_updateCorrectly() {
|
||||
List<AccessPoint> accessPointList = spy(new ArrayList<>());
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KEY_SSID, "Test AP 1");
|
||||
accessPointList.add(new AccessPoint(mContext, bundle));
|
||||
bundle.putString(KEY_SSID, "Test AP 2");
|
||||
accessPointList.add(new AccessPoint(mContext, bundle));
|
||||
bundle.putString(KEY_SSID, "Test AP 3");
|
||||
accessPointList.add(new AccessPoint(mContext, bundle));
|
||||
bundle.putString(KEY_SSID, "Test AP 4");
|
||||
accessPointList.add(new AccessPoint(mContext, bundle));
|
||||
|
||||
public void updateAccessPointList_onUserSelectionConnectSuccess_shouldCloseTheDialog() {
|
||||
List<AccessPoint> accessPointList = createAccessPointList();
|
||||
when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
|
||||
networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
|
||||
AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||
assertThat(alertDialog.isShowing()).isTrue();
|
||||
|
||||
// Test if config would update list.
|
||||
WifiConfiguration config = new WifiConfiguration();
|
||||
config.SSID = "Test AP 3";
|
||||
networkRequestDialogFragment.onUserSelectionConnectSuccess(config);
|
||||
|
||||
AccessPoint verifyAccessPoint = new AccessPoint(mContext, config);
|
||||
verify(accessPointList, times(1)).set(2, verifyAccessPoint);
|
||||
assertThat(alertDialog.isShowing()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateAccessPointList_onUserSelectionConnectFailure_updateCorrectly() {
|
||||
List<AccessPoint> accessPointList = spy(new ArrayList<>());
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KEY_SSID, "Test AP 1");
|
||||
accessPointList.add(new AccessPoint(mContext, bundle));
|
||||
bundle.putString(KEY_SSID, "Test AP 2");
|
||||
accessPointList.add(new AccessPoint(mContext, bundle));
|
||||
bundle.putString(KEY_SSID, "Test AP 3");
|
||||
accessPointList.add(new AccessPoint(mContext, bundle));
|
||||
bundle.putString(KEY_SSID, "Test AP 4");
|
||||
accessPointList.add(new AccessPoint(mContext, bundle));
|
||||
public void updateAccessPointList_onUserSelectionConnectFailure_shouldCallTimeoutDialog() {
|
||||
FakeNetworkRequestDialogFragment fakeFragment = new FakeNetworkRequestDialogFragment();
|
||||
FakeNetworkRequestDialogFragment spyFakeFragment = spy(fakeFragment);
|
||||
List<AccessPoint> accessPointList = createAccessPointList();
|
||||
when(spyFakeFragment.getAccessPointList()).thenReturn(accessPointList);
|
||||
spyFakeFragment.show(mActivity.getSupportFragmentManager(), null);
|
||||
|
||||
when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
|
||||
networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
|
||||
AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||
assertThat(alertDialog.isShowing()).isTrue();
|
||||
|
||||
// Test if config would update list.
|
||||
WifiConfiguration config = new WifiConfiguration();
|
||||
config.SSID = "Test AP 3";
|
||||
networkRequestDialogFragment.onUserSelectionConnectFailure(config);
|
||||
fakeFragment.onUserSelectionConnectFailure(config);
|
||||
|
||||
AccessPoint verifyAccessPoint = new AccessPoint(mContext, config);
|
||||
verify(accessPointList, times(1)).set(2, verifyAccessPoint);
|
||||
assertThat(fakeFragment.bCalledStopAndPop).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUserSelectionCallbackRegistration_shouldCallSelect() {
|
||||
List<AccessPoint> accessPointList = spy(new ArrayList<>());
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KEY_SSID, "Test AP 1");
|
||||
accessPointList.add(new AccessPoint(mContext, bundle));
|
||||
bundle.putString(KEY_SSID, "Test AP 2");
|
||||
accessPointList.add(new AccessPoint(mContext, bundle));
|
||||
|
||||
bundle.putString(KEY_SSID, "Test AP 3");
|
||||
AccessPoint clickedAccessPoint = new AccessPoint(mContext, bundle);
|
||||
public void onUserSelectionCallbackRegistration_onClick_shouldCallSelect() {
|
||||
// Assert.
|
||||
final int indexClickItem = 3;
|
||||
List<AccessPoint> accessPointList = createAccessPointList();
|
||||
AccessPoint clickedAccessPoint = accessPointList.get(indexClickItem);
|
||||
clickedAccessPoint.generateOpenNetworkConfig();
|
||||
accessPointList.add(clickedAccessPoint);
|
||||
|
||||
bundle.putString(KEY_SSID, "Test AP 4");
|
||||
accessPointList.add(new AccessPoint(mContext, bundle));
|
||||
when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
|
||||
|
||||
NetworkRequestUserSelectionCallback selectionCallback = mock(
|
||||
@@ -212,40 +197,66 @@ public class NetworkRequestDialogFragmentTest {
|
||||
AlertDialog dialog = mock(AlertDialog.class);
|
||||
networkRequestDialogFragment.onUserSelectionCallbackRegistration(selectionCallback);
|
||||
|
||||
networkRequestDialogFragment.onClick(dialog, 2);
|
||||
// Act.
|
||||
networkRequestDialogFragment.onClick(dialog, indexClickItem);
|
||||
|
||||
// Check.
|
||||
verify(selectionCallback, times(1)).select(clickedAccessPoint.getConfig());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMatch_shouldUpdatedList() {
|
||||
// Prepares WifiManager.
|
||||
// Assert.
|
||||
when(networkRequestDialogFragment.getContext()).thenReturn(mContext);
|
||||
Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext());
|
||||
when(mContext.getApplicationContext()).thenReturn(applicationContext);
|
||||
WifiManager wifiManager = mock(WifiManager.class);
|
||||
when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager);
|
||||
networkRequestDialogFragment.onResume();
|
||||
|
||||
List<AccessPoint> accessPointList = createAccessPointList();
|
||||
when(mWifiTracker.getAccessPoints()).thenReturn(accessPointList);
|
||||
|
||||
List<WifiConfiguration> wifiConfigurationList = new ArrayList<>();
|
||||
WifiConfiguration config = new WifiConfiguration();
|
||||
final String SSID_AP1 = "Test AP 1";
|
||||
config.SSID = SSID_AP1;
|
||||
wifiConfigurationList.add(config);
|
||||
config = new WifiConfiguration();
|
||||
final String SSID_AP2 = "Test AP 2";
|
||||
config.SSID = SSID_AP2;
|
||||
wifiConfigurationList.add(config);
|
||||
|
||||
// Prepares callback converted data.
|
||||
List<ScanResult> scanResults = new ArrayList<>();
|
||||
when(wifiManager.getAllMatchingWifiConfigs(scanResults)).thenReturn(wifiConfigurationList);
|
||||
ScanResult scanResult = new ScanResult();
|
||||
scanResult.SSID = SSID_AP1;
|
||||
scanResult.capabilities = "WEP";
|
||||
scanResults.add(scanResult);
|
||||
scanResult = new ScanResult();
|
||||
scanResult.SSID = SSID_AP2;
|
||||
scanResult.capabilities = "WEP";
|
||||
scanResults.add(scanResult);
|
||||
|
||||
// Act.
|
||||
networkRequestDialogFragment.onMatch(scanResults);
|
||||
|
||||
List<AccessPoint> accessPointList = networkRequestDialogFragment.getAccessPointList();
|
||||
assertThat(accessPointList).isNotEmpty();
|
||||
assertThat(accessPointList.size()).isEqualTo(2);
|
||||
assertThat(accessPointList.get(0).getSsid()).isEqualTo(SSID_AP1);
|
||||
assertThat(accessPointList.get(1).getSsid()).isEqualTo(SSID_AP2);
|
||||
// Check.
|
||||
List<AccessPoint> returnList = networkRequestDialogFragment.getAccessPointList();
|
||||
assertThat(returnList).isNotEmpty();
|
||||
assertThat(returnList.size()).isEqualTo(2);
|
||||
assertThat(returnList.get(0).getSsid()).isEqualTo(SSID_AP1);
|
||||
assertThat(returnList.get(1).getSsid()).isEqualTo(SSID_AP2);
|
||||
}
|
||||
|
||||
private List<AccessPoint> createAccessPointList() {
|
||||
List<AccessPoint> accessPointList = spy(new ArrayList<>());
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KEY_SSID, "Test AP 1");
|
||||
bundle.putInt(KEY_SECURITY, 1);
|
||||
accessPointList.add(new AccessPoint(mContext, bundle));
|
||||
bundle.putString(KEY_SSID, "Test AP 2");
|
||||
bundle.putInt(KEY_SECURITY, 1);
|
||||
accessPointList.add(new AccessPoint(mContext, bundle));
|
||||
bundle.putString(KEY_SSID, "Test AP 3");
|
||||
bundle.putInt(KEY_SECURITY, 2);
|
||||
AccessPoint clickedAccessPoint = new AccessPoint(mContext, bundle);
|
||||
accessPointList.add(clickedAccessPoint);
|
||||
bundle.putString(KEY_SSID, "Test AP 4");
|
||||
bundle.putInt(KEY_SECURITY, 0);
|
||||
accessPointList.add(new AccessPoint(mContext, bundle));
|
||||
|
||||
return accessPointList;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user