Merge "GUP: Display a list of Apps and dialogs"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 871f609..69a67ad 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -139,7 +139,11 @@
android:label="@string/network_settings_title"
android:theme="@style/Theme.Settings.Home"
android:launchMode="singleTask">
- <!-- TODO(b/114749736): add intent filter here and disable the one in telephony -->
+ <intent-filter android:priority="1">
+ <action android:name="android.settings.NETWORK_OPERATOR_SETTINGS" />
+ <action android:name="android.settings.DATA_ROAMING_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
</activity>
<!-- Alias for launcher activity only, as this belongs to each profile. -->
@@ -2003,9 +2007,8 @@
</intent-filter>
</activity>
- <!-- TODO: Is this needed? -->
<activity android:name="BandMode"
- android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert"
+ android:label="@string/band_mode_title"
android:process="com.android.phone">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -3050,7 +3053,7 @@
<intent-filter>
<action android:name="android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_SCANNER"/>
<action android:name="android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_GENERATOR"/>
- <action android:name="android.settings.WIFI_DPP_CONFIGURATOR_CHOOSE_SAVED_WIFI_NETWORK"/>
+ <action android:name="android.settings.PROCESS_WIFI_DPP_QR_CODE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
diff --git a/color-check-baseline.xml b/color-check-baseline.xml
index fd0fc6c..7b0b28e 100644
--- a/color-check-baseline.xml
+++ b/color-check-baseline.xml
@@ -2,6 +2,18 @@
<issues format="4">
<issue
+ id="LintError"
+ severity="Error"
+ message="No `.class` files were found in project ".", so none of the classfile based checks could be run. Does the project need to be built first?"
+ category="Lint"
+ priority="10"
+ summary="Lint Failure"
+ explanation="This issue type represents a problem running lint itself. Examples include failure to find bytecode for source files (which means certain detectors could not be run), parsing errors in lint configuration files, etc.
These errors are not errors in your own code, but they are shown to make it clear that some checks were not completed.">
+ <location
+ file="."/>
+ </issue>
+
+ <issue
id="HardCodedColor"
severity="Error"
message="Avoid using hardcoded color"
@@ -233,6 +245,22 @@
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <color name="homepage_status_bar_color">#cc000000</color>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/values-night/colors.xml"
+ line="25"
+ column="3"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" <color name="crypt_keeper_clock_foreground">#ff666666</color>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
@@ -1289,11 +1317,27 @@
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <color name="homepage_status_bar_color">#ccFFFFFF</color>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/values/colors.xml"
+ line="133"
+ column="5"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" <color name="qr_corner_line_color">#ffdadce0</color>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
- line="133"
+ line="136"
column="5"/>
</issue>
@@ -1309,7 +1353,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
- line="134"
+ line="137"
column="5"/>
</issue>
@@ -1325,7 +1369,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
- line="135"
+ line="138"
column="5"/>
</issue>
@@ -2477,7 +2521,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/strings.xml"
- line="5883"
+ line="5885"
column="36"/>
</issue>
@@ -2509,7 +2553,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="415"
+ line="388"
column="44"/>
</issue>
@@ -2525,7 +2569,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="421"
+ line="394"
column="44"/>
</issue>
@@ -2541,7 +2585,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="422"
+ line="395"
column="44"/>
</issue>
@@ -2557,7 +2601,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="457"
+ line="430"
column="34"/>
</issue>
diff --git a/res/layout/band_mode.xml b/res/layout/band_mode.xml
index ddbc7ae..b43dd1d 100644
--- a/res/layout/band_mode.xml
+++ b/res/layout/band_mode.xml
@@ -19,7 +19,7 @@
android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="wrap_content">
<ListView android:id="@+id/band"
android:layout_width="match_parent"
diff --git a/res/layout/homepage_dismissal_view.xml b/res/layout/homepage_dismissal_view.xml
index e60b375..7d1abf3 100644
--- a/res/layout/homepage_dismissal_view.xml
+++ b/res/layout/homepage_dismissal_view.xml
@@ -20,6 +20,7 @@
android:id="@+id/dismissal_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="@color/homepage_card_dismissal_background"
android:orientation="vertical">
<TextView
@@ -40,6 +41,7 @@
style="@style/ContextualCardDismissalButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/homepage_card_dismissal_margin_bottom"
android:text="@string/contextual_card_dismiss_keep"/>
<Button
@@ -47,6 +49,7 @@
style="@style/ContextualCardDismissalButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/homepage_card_dismissal_margin_bottom"
android:text="@string/contextual_card_dismiss_remove"/>
</LinearLayout>
diff --git a/res/layout/homepage_slice_half_tile.xml b/res/layout/homepage_slice_half_tile.xml
index 7de9eb6..46f3cda 100644
--- a/res/layout/homepage_slice_half_tile.xml
+++ b/res/layout/homepage_slice_half_tile.xml
@@ -24,12 +24,12 @@
<ViewFlipper
android:id="@+id/view_flipper"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="match_parent">
<LinearLayout
android:id="@+id/content"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:paddingStart="@dimen/homepage_card_padding_start"
android:paddingEnd="@dimen/homepage_card_padding_end"
android:paddingTop="@dimen/homepage_half_card_padding_top"
diff --git a/res/layout/homepage_slice_tile.xml b/res/layout/homepage_slice_tile.xml
index 9fa7d61..2b7c1b0 100644
--- a/res/layout/homepage_slice_tile.xml
+++ b/res/layout/homepage_slice_tile.xml
@@ -30,6 +30,7 @@
android:id="@+id/slice_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
android:paddingStart="@dimen/homepage_card_padding_start"
android:paddingEnd="@dimen/homepage_card_padding_end"/>
diff --git a/res/layout/manage_applications_apps.xml b/res/layout/manage_applications_apps.xml
index 765ced6..c2f58c3 100644
--- a/res/layout/manage_applications_apps.xml
+++ b/res/layout/manage_applications_apps.xml
@@ -14,60 +14,73 @@
limitations under the License.
-->
-<LinearLayout
+<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
- <FrameLayout
+ <androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1">
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ settings:layout_behavior="com.android.settings.widget.FloatingAppBarScrollingViewBehavior">
- <LinearLayout
- android:id="@+id/list_container"
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
- android:visibility="gone">
+ android:paddingTop="@dimen/app_bar_height">
- <FrameLayout
- android:id="@+id/pinned_header"
+ <LinearLayout
+ android:id="@+id/list_container"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:visibility="gone">
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="0px"
- android:layout_weight="1">
-
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/apps_list"
+ <FrameLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
- settings:fastScrollEnabled="true"
- settings:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
- settings:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
- settings:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
- settings:fastScrollVerticalTrackDrawable="@drawable/line_drawable"/>
+ android:layout_height="match_parent">
- <TextView
- android:id="@android:id/empty"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:text="@string/no_applications"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:visibility="invisible" />
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/apps_list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ settings:fastScrollEnabled="true"
+ settings:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
+ settings:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
+ settings:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
+ settings:fastScrollVerticalTrackDrawable="@drawable/line_drawable"/>
- </FrameLayout>
+ <TextView
+ android:id="@android:id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:text="@string/no_applications"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:visibility="invisible"/>
- </LinearLayout>
+ </FrameLayout>
- <include layout="@layout/loading_container" />
+ </LinearLayout>
- </FrameLayout>
+ <include layout="@layout/loading_container"/>
-</LinearLayout>
+ </FrameLayout>
+
+ </androidx.core.widget.NestedScrollView>
+
+ <com.google.android.material.appbar.AppBarLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <FrameLayout
+ android:id="@+id/pinned_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ settings:layout_scrollFlags="scroll|enterAlways"/>
+ </com.google.android.material.appbar.AppBarLayout>
+
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/res/layout/settings_homepage_container.xml b/res/layout/settings_homepage_container.xml
index 75d449f..1e5bdce 100644
--- a/res/layout/settings_homepage_container.xml
+++ b/res/layout/settings_homepage_container.xml
@@ -31,8 +31,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingTop="@dimen/app_bar_height"
- android:descendantFocusability="blocksDescendants">
+ android:descendantFocusability="blocksDescendants"
+ android:paddingTop="104dp">
+ <!-- height of status bar(24dp) + height of action bar(48dp) + top/bottom margins(16dp) -->
<FrameLayout
android:id="@+id/contextual_cards_content"
@@ -52,6 +53,13 @@
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="@*android:dimen/status_bar_height"
+ android:background="@android:color/transparent"
+ app:layout_scrollFlags="scroll|enterAlways"/>
+
<include layout="@layout/search_bar"/>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/res/layout/time_zone_search_item.xml b/res/layout/time_zone_search_item.xml
index bb75226..8d059a8 100644
--- a/res/layout/time_zone_search_item.xml
+++ b/res/layout/time_zone_search_item.xml
@@ -63,7 +63,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
- android:textAppearance="@style/Preference_TextAppearanceMaterialSubhead"
+ android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee" />
<RelativeLayout
diff --git a/res/layout/wifi_dialog.xml b/res/layout/wifi_dialog.xml
index 2a395b6..df676fc 100644
--- a/res/layout/wifi_dialog.xml
+++ b/res/layout/wifi_dialog.xml
@@ -68,7 +68,7 @@
android:layout_centerVertical="true"
android:layout_margin="5dp"
android:background="@null"
- android:src="@drawable/ic_qrcode_24dp"
+ android:src="@drawable/ic_scan_24dp"
android:visibility="gone"
android:contentDescription="@string/wifi_add_network" />
</RelativeLayout>
@@ -303,7 +303,7 @@
android:layout_centerVertical="true"
android:layout_margin="5dp"
android:background="@null"
- android:src="@drawable/ic_qrcode_24dp"
+ android:src="@drawable/ic_scan_24dp"
android:visibility="gone"
android:contentDescription="@string/wifi_add_network" />
</RelativeLayout>
diff --git a/res/layout/wifi_dpp_add_device_fragment.xml b/res/layout/wifi_dpp_add_device_fragment.xml
index 03add62..5e70396 100644
--- a/res/layout/wifi_dpp_add_device_fragment.xml
+++ b/res/layout/wifi_dpp_add_device_fragment.xml
@@ -24,22 +24,19 @@
<include layout="@layout/wifi_dpp_fragment_header"/>
- <ProgressBar
- android:id="@+id/progress_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:indeterminate="true"/>
-
<ImageView
android:id="@+id/wifi_ap_picture_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"/>
- <TextView android:id="@+id/choose_different_network"
+ <TextView
+ android:id="@+id/choose_different_network"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"/>
+ android:layout_gravity="center"
+ android:layout_marginTop="8dp"
+ android:text="@string/wifi_dpp_choose_different_network"/>
<include layout="@layout/wifi_dpp_fragment_footer"
android:gravity="center|bottom"/>
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index bc06f47..cdbeada 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -21,5 +21,8 @@
<color name="switchbar_switch_thumb_tint">@android:color/black</color>
<color name="homepage_accessibility_background">#783BE5</color>
<color name="homepage_support_background">#3F5FBD</color>
+ <!-- 80% black for status bar of homepage -->
+ <color name="homepage_status_bar_color">#cc000000</color>
+ <color name="homepage_card_dismissal_background">@*android:color/material_grey_800</color>
</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 2103649..a1381c3 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -104,6 +104,7 @@
<color name="homepage_about_background">#9FA8DA</color>
<color name="homepage_privacy_background">#5E97F6</color>
<color name="homepage_card_stroke_color">#1f000000</color>
+ <color name="homepage_card_dismissal_background">@*android:color/material_grey_50</color>
<!-- End of dashboard/homepage icon background colors -->
<color name="switchbar_text_color">@android:color/white</color>
@@ -129,6 +130,9 @@
<!-- launcher icon color -->
<color name="icon_launcher_setting_color">@*android:color/accent_device_default_light</color>
+ <!-- 80% white for status bar of homepage -->
+ <color name="homepage_status_bar_color">#ccFFFFFF</color>
+
<!-- QR code scanner colors -->
<color name="qr_corner_line_color">#ffdadce0</color>
<color name="qr_focused_corner_line_color">#ff1a73e8</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index 82e185c..8efa6b2 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -171,4 +171,7 @@
<!-- ComponentName to launch a vendor-specific enrollment activity if available -->
<string name="config_face_enroll" translatable="false"></string>
+
+ <!-- Max allowed value for screen timeout, in milliseconds -->
+ <integer name="max_lock_after_timeout_ms">1800000</integer>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 383f564..1a3d6ff 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -105,8 +105,6 @@
<dimen name="search_bar_avatar_size">32dp</dimen>
<dimen name="search_bar_avatar_start_margin">4dp</dimen>
<dimen name="search_bar_avatar_end_margin">16dp</dimen>
- <!-- appbar height is equal search bar height (48dp) plus search bar top and bottom margin -->
- <dimen name="app_bar_height">80dp</dimen>
<!-- Dimensions for Wifi Assistant Card -->
<dimen name="wifi_assistant_padding_top_bottom">16dp</dimen>
@@ -116,6 +114,8 @@
<dimen name="wifi_assistant_height">182dp</dimen>
<dimen name="wifi_assistant_image_top">32dp</dimen>
<dimen name="wifi_assistant_image_start">24dp</dimen>
+ <!-- appbar height is equal search bar height (48dp) plus search bar top and bottom margin -->
+ <dimen name="app_bar_height">80dp</dimen>
<!-- CryptKeeper top margin for password/pin screen -->
<dimen name="crypt_keeper_password_top_margin">88dip</dimen>
@@ -332,6 +332,7 @@
<dimen name="homepage_half_card_padding_top">12dp</dimen>
<dimen name="homepage_half_card_padding_bottom">16dp</dimen>
<dimen name="homepage_half_card_title_margin_top">12dp</dimen>
+ <dimen name="homepage_card_dismissal_margin_bottom">2dp</dimen>
<!-- Horizontal divider size and margin -->
<dimen name="horizontal_divider_margin_top">4dp</dimen>
@@ -355,7 +356,7 @@
<dimen name="homepage_condition_full_card_padding_bottom">12dp</dimen>
<dimen name="homepage_condition_header_padding_top">10dp</dimen>
<dimen name="homepage_condition_header_padding_bottom">10dp</dimen>
- <dimen name="homepage_condition_header_icons_margin_start">24dp</dimen>
+ <dimen name="homepage_condition_header_icons_margin_start">16dp</dimen>
<dimen name="homepage_condition_header_indicator_padding_top">4dp</dimen>
<dimen name="homepage_condition_header_indicator_padding_start">16dp</dimen>
<dimen name="homepage_condition_header_indicator_padding_end">16dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8868b4b..88fe4eb 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2077,13 +2077,13 @@
<!-- Label for the spinner to show Wifi MAC randomization [CHAR LIMIT=25] -->
<string name="wifi_privacy_settings">Privacy</string>
<!-- Title for the fragment to add a device into the wifi network [CHAR LIMIT=50] -->
- <string name="wifi_dpp_add_device_to_network">Add a device to this network</string>
+ <string name="wifi_dpp_add_device_to_network">Add a device</string>
<!-- Hint for the user to center another device's QR code in the below camera window [CHAR LIMIT=120] -->
- <string name="wifi_dpp_center_qr_code">Center the device\u2019s QR code below to add device to \u201c<xliff:g id="ssid" example="OfficeWifi">%1$s</xliff:g>\u201d</string>
+ <string name="wifi_dpp_center_qr_code">Center the QR code below to add the device to \u201c<xliff:g id="ssid" example="OfficeWifi">%1$s</xliff:g>\u201d</string>
<!-- Title for the fragment to scan QR code [CHAR LIMIT=50] -->
<string name="wifi_dpp_scan_qr_code">Scan QR code</string>
<!-- Hint for the user to center another device's QR code in the below camera window [CHAR LIMIT=NONE] -->
- <string name="wifi_dpp_scan_qr_code_join_network">Join \u201c<xliff:g id="ssid" example="OfficeWifi">%1$s</xliff:g>\u201d by scanning a QR code</string>
+ <string name="wifi_dpp_scan_qr_code_join_network">Center the QR code below to connect to \u201c<xliff:g id="ssid" example="OfficeWifi">%1$s</xliff:g>\u201d</string>
<!-- Hint for the user to center another device's QR code in the below camera window [CHAR LIMIT=NONE] -->
<string name="wifi_dpp_scan_qr_code_join_unknown_network">Join Wi\u2011Fi by scanning a QR code</string>
<!-- Title for the fragment to share Wi-Fi [CHAR LIMIT=50] -->
@@ -2091,7 +2091,19 @@
<!-- Hint for the user to use another device to scan QR code on screen to join Wi-Fi [CHAR LIMIT=NONE] -->
<string name="wifi_dpp_scan_qr_code_with_another_device">Scan this QR code with another device to join \u201c<xliff:g id="ssid" example="OfficeWifi">%1$s</xliff:g>\u201d</string>
<!-- Hint for QR code detection [CHAR LIMIT=NONE] -->
- <string name="wifi_dpp_could_not_detect_valid_qr_code">Could not detect valid QR code</string>
+ <string name="wifi_dpp_could_not_detect_valid_qr_code">Couldn\u2019t read QR code</string>
+ <!-- Title for the fragment choose network [CHAR LIMIT=50] -->
+ <string name="wifi_dpp_choose_network">Choose network</string>
+ <!-- Hint for the user to center another device's QR code in the below camera window [CHAR LIMIT=NONE] -->
+ <string name="wifi_dpp_choose_network_to_connect_device">To connect your device, choose a network</string>
+ <!-- Hint for the user to add the device to a Wi-Fi network [CHAR LIMIT=NONE] -->
+ <string name="wifi_dpp_add_device_to_wifi">Add this device to \u201c<xliff:g id="ssid" example="OfficeWifi">%1$s</xliff:g>\u201d?</string>
+ <!-- Title for the fragment to tell the user that Wi-Fi shared with device successfully [CHAR LIMIT=50] -->
+ <string name="wifi_dpp_wifi_shared_with_device">Wi\u2011Fi shared with device</string>
+ <!-- Button label to add another device to Wi-Fi [CHAR LIMIT=50] -->
+ <string name="wifi_dpp_add_another_device">Add another device</string>
+ <!-- Button label to choose different Wi-Fi network [CHAR LIMIT=80] -->
+ <string name="wifi_dpp_choose_different_network">Choose different network</string>
<!-- Label for the check box to share a network with other users on the same device -->
<string name="wifi_shared">Share with other device users</string>
<!-- Hint for unchanged fields -->
@@ -5816,9 +5828,6 @@
Used in SetupWizard for XLarge screen [CHAR LIMIT=20] -->
<string name="wifi_setup_detail">Network details</string>
- <!-- Do not translate. This is a stub which will be removed soon. -->
- <string name="time_zone_auto_stub" translatable="false">Select Time Zone</string>
-
<!-- Content description of the enabled sync icon for accessibility. [CHAR LIMIT=NONE] -->
<string name="accessibility_sync_enabled">Sync enabled</string>
<!-- Content description of the disabled sync icon for accessibility. [CHAR LIMIT=NONE] -->
@@ -7130,8 +7139,8 @@
<!-- Sound: Other sounds: Title for the option enabling touch sounds for screen locking sounds. [CHAR LIMIT=30] -->
<string name="screen_locking_sounds_title">Screen locking sounds</string>
- <!-- Sound: Other sounds: Title for the option enabling charging sounds. [CHAR LIMIT=30] -->
- <string name="charging_sounds_title">Charging sounds</string>
+ <!-- Sound: Other sounds: Title for the option enabling charging sounds and vibration. [CHAR LIMIT=30] -->
+ <string name="charging_sounds_title">Charging sounds and vibration</string>
<!-- Sound: Other sounds: Title for the option enabling docking sounds. [CHAR LIMIT=30] -->
<string name="docking_sounds_title">Docking sounds</string>
@@ -9461,10 +9470,14 @@
<string name="notification_log_details_parcel">parcel size</string>
<!-- Notification log debug tool: notification ashmem size -->
<string name="notification_log_details_ashmem">ashmem</string>
+ <!-- Notification log debug tool: header: notification alert info -->
+ <string name="notification_log_details_alerted">notification alerted</string>
<!-- Notification log debug tool: header: notification sound info -->
<string name="notification_log_details_sound">sound</string>
<!-- Notification log debug tool: header: notification vibration info -->
<string name="notification_log_details_vibrate">vibrate</string>
+ <!-- Notification log debug tool: header: notification vibration info -->
+ <string name="notification_log_details_vibrate_pattern">pattern</string>
<!-- Notification log debug tool: the word 'default' -->
<string name="notification_log_details_default">default</string>
<!-- Notification log debug tool: the word 'none' -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 98b6283..111cdbd 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -454,11 +454,13 @@
<style name="ConditionFullCardBorderlessButton"
parent="@style/ConditionCardBorderlessButton">
- <item name="android:textAlignment">viewEnd</item>
+ <item name="android:minWidth">24dp</item>
+ <item name="android:layout_marginStart">20dp</item>
</style>
<style name="ContextualCardDismissalButton"
parent="android:Widget.DeviceDefault.Button.Borderless.Colored">
+ <item name="android:minHeight">16dp</item>
<item name="android:textAllCaps">false</item>
</style>
diff --git a/res/xml/date_time_prefs.xml b/res/xml/date_time_prefs.xml
index edda1ba..e8af64c 100644
--- a/res/xml/date_time_prefs.xml
+++ b/res/xml/date_time_prefs.xml
@@ -58,7 +58,7 @@
<com.android.settingslib.RestrictedPreference
android:fragment="com.android.settings.datetime.timezone.TimeZoneSettings"
android:key="timezone"
- android:title="@string/date_time_set_timezone"
+ android:title="@string/date_time_set_timezone_title"
android:summary="@string/summary_placeholder"
settings:userRestriction="no_config_date_time" />
</PreferenceCategory>
diff --git a/res/xml/prevent_ringing_gesture_settings.xml b/res/xml/prevent_ringing_gesture_settings.xml
index 62f0223..4b0edc3 100644
--- a/res/xml/prevent_ringing_gesture_settings.xml
+++ b/res/xml/prevent_ringing_gesture_settings.xml
@@ -26,8 +26,11 @@
app:animation="@raw/gesture_prevent_ringing"
app:preview="@drawable/gesture_prevent_ringing" />
+ <com.android.settingslib.widget.LayoutPreference
+ android:key="gesture_prevent_ringing_switch"
+ android:layout="@layout/styled_switch_bar" />
+
<PreferenceCategory
android:key="gesture_prevent_ringing_category"
- android:title="@string/gesture_prevent_ringing_title">
- </PreferenceCategory>
+ android:title="@string/gesture_prevent_ringing_title" />
</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/privacy_dashboard_settings.xml b/res/xml/privacy_dashboard_settings.xml
index 79e2e71..a580f5f 100644
--- a/res/xml/privacy_dashboard_settings.xml
+++ b/res/xml/privacy_dashboard_settings.xml
@@ -19,7 +19,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="privacy_dashboard_page"
- android:title="@string/privacy_dashboard_title">
+ android:title="@string/privacy_dashboard_title"
+ settings:initialExpandedChildrenCount="3">
<!-- App permissions -->
<Preference
@@ -30,13 +31,6 @@
<intent android:action="android.intent.action.MANAGE_PERMISSIONS"/>
</Preference>
- <!-- On lock screen notifications -->
- <com.android.settings.RestrictedListPreference
- android:key="privacy_lock_screen_notifications"
- android:title="@string/lock_screen_notifications_title"
- android:summary="@string/summary_placeholder"
- settings:searchable="false"/>
-
<!-- Show passwords -->
<SwitchPreference
android:key="show_password"
@@ -44,6 +38,13 @@
android:summary="@string/show_password_summary"
settings:controller="com.android.settings.security.ShowPasswordPreferenceController"/>
+ <!-- On lock screen notifications -->
+ <com.android.settings.RestrictedListPreference
+ android:key="privacy_lock_screen_notifications"
+ android:title="@string/lock_screen_notifications_title"
+ android:summary="@string/summary_placeholder"
+ settings:searchable="false"/>
+
<!-- Privacy Service -->
<PreferenceCategory
android:key="privacy_services"/>
diff --git a/src/com/android/settings/BandMode.java b/src/com/android/settings/BandMode.java
index 5be82f6..bae8860 100644
--- a/src/com/android/settings/BandMode.java
+++ b/src/com/android/settings/BandMode.java
@@ -73,13 +73,8 @@
super.onCreate(icicle);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
-
setContentView(R.layout.band_mode);
- setTitle(getString(R.string.band_mode_title));
- getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.WRAP_CONTENT);
-
mPhone = PhoneFactory.getDefaultPhone();
mBandList = (ListView) findViewById(R.id.band);
diff --git a/src/com/android/settings/development/featureflags/FeatureFlagPersistent.java b/src/com/android/settings/development/featureflags/FeatureFlagPersistent.java
index d27af64..33de9c3 100644
--- a/src/com/android/settings/development/featureflags/FeatureFlagPersistent.java
+++ b/src/com/android/settings/development/featureflags/FeatureFlagPersistent.java
@@ -37,6 +37,7 @@
static {
PERSISTENT_FLAGS = new HashSet<>();
PERSISTENT_FLAGS.add(FeatureFlags.HEARING_AID_SETTINGS);
+ PERSISTENT_FLAGS.add(FeatureFlags.NETWORK_INTERNET_V2);
}
public static boolean isEnabled(Context context, String feature) {
diff --git a/src/com/android/settings/display/TimeoutListPreference.java b/src/com/android/settings/display/TimeoutListPreference.java
index f9a731d..5ed427f 100644
--- a/src/com/android/settings/display/TimeoutListPreference.java
+++ b/src/com/android/settings/display/TimeoutListPreference.java
@@ -26,6 +26,7 @@
import android.util.Log;
import android.view.View;
+import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog.Builder;
import com.android.settings.R;
@@ -33,18 +34,18 @@
import com.android.settingslib.RestrictedLockUtils;
import java.util.ArrayList;
+import java.util.List;
public class TimeoutListPreference extends RestrictedListPreference {
private static final String TAG = "TimeoutListPreference";
private EnforcedAdmin mAdmin;
- private final CharSequence[] mInitialEntries;
- private final CharSequence[] mInitialValues;
+ private CharSequence[] mInitialEntries;
+ private CharSequence[] mInitialValues;
public TimeoutListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
- mInitialEntries = getEntries();
- mInitialValues = getEntryValues();
+ updateInitialValues();
}
@Override
@@ -65,13 +66,8 @@
if (mAdmin != null) {
View footerView = dialog.findViewById(R.id.admin_disabled_other_options);
footerView.findViewById(R.id.admin_more_details_link).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
- getContext(), mAdmin);
- }
- });
+ view -> RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
+ getContext(), mAdmin));
}
}
@@ -89,8 +85,8 @@
maxTimeout = Long.MAX_VALUE;
}
- ArrayList<CharSequence> revisedEntries = new ArrayList<CharSequence>();
- ArrayList<CharSequence> revisedValues = new ArrayList<CharSequence>();
+ final ArrayList<CharSequence> revisedEntries = new ArrayList<>();
+ final ArrayList<CharSequence> revisedValues = new ArrayList<>();
for (int i = 0; i < mInitialValues.length; ++i) {
long timeout = Long.parseLong(mInitialValues[i].toString());
if (timeout <= maxTimeout) {
@@ -101,7 +97,7 @@
// If there are no possible options for the user, then set this preference as disabled
// by admin, otherwise remove the padlock in case it was set earlier.
- if (revisedValues.size() == 0) {
+ if (revisedValues.isEmpty()) {
setDisabledByAdmin(admin);
return;
} else {
@@ -117,7 +113,7 @@
setValue(String.valueOf(userPreference));
} else if (revisedValues.size() > 0
&& Long.parseLong(revisedValues.get(revisedValues.size() - 1).toString())
- == maxTimeout) {
+ == maxTimeout) {
// If the last one happens to be the same as the max timeout, select that
setValue(String.valueOf(maxTimeout));
} else {
@@ -128,4 +124,36 @@
}
}
}
+
+ @VisibleForTesting
+ void updateInitialValues() {
+ // Read default list of candidate values.
+ final CharSequence[] entries = getEntries();
+ final CharSequence[] values = getEntryValues();
+ // Filter out values based on config
+ final List<CharSequence> revisedEntries = new ArrayList<>();
+ final List<CharSequence> revisedValues = new ArrayList<>();
+ final long maxTimeout = getContext().getResources().getInteger(
+ R.integer.max_lock_after_timeout_ms);
+ if (entries == null || values == null) {
+ return;
+ }
+ Log.d(TAG, "max timeout: " + maxTimeout);
+ for (int i = 0; i < values.length; ++i) {
+ long timeout = Long.parseLong(values[i].toString());
+ if (timeout <= maxTimeout) {
+ Log.d(TAG, "keeping timeout: " + values[i]);
+ revisedEntries.add(entries[i]);
+ revisedValues.add(values[i]);
+ } else {
+ Log.d(TAG, "Dropping timeout: " + values[i]);
+ }
+ }
+
+ // Store final candidates in initial value lists.
+ mInitialEntries = revisedEntries.toArray(new CharSequence[0]);
+ setEntries(mInitialEntries);
+ mInitialValues = revisedValues.toArray(new CharSequence[0]);
+ setEntryValues(mInitialValues);
+ }
}
diff --git a/src/com/android/settings/display/TimeoutPreferenceController.java b/src/com/android/settings/display/TimeoutPreferenceController.java
index 60b7e24..c1c5069 100644
--- a/src/com/android/settings/display/TimeoutPreferenceController.java
+++ b/src/com/android/settings/display/TimeoutPreferenceController.java
@@ -13,8 +13,6 @@
*/
package com.android.settings.display;
-import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.os.UserHandle;
@@ -60,7 +58,7 @@
public void updateState(Preference preference) {
final TimeoutListPreference timeoutListPreference = (TimeoutListPreference) preference;
final long currentTimeout = Settings.System.getLong(mContext.getContentResolver(),
- SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE);
+ Settings.System.SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE);
timeoutListPreference.setValue(String.valueOf(currentTimeout));
final DevicePolicyManager dpm =
(DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
@@ -86,7 +84,8 @@
public boolean onPreferenceChange(Preference preference, Object newValue) {
try {
int value = Integer.parseInt((String) newValue);
- Settings.System.putInt(mContext.getContentResolver(), SCREEN_OFF_TIMEOUT, value);
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_OFF_TIMEOUT, value);
updateTimeoutPreferenceDescription((TimeoutListPreference) preference, value);
} catch (NumberFormatException e) {
Log.e(TAG, "could not persist screen timeout setting", e);
@@ -94,7 +93,7 @@
return true;
}
- public static CharSequence getTimeoutDescription(
+ private static CharSequence getTimeoutDescription(
long currentTimeout, CharSequence[] entries, CharSequence[] values) {
if (currentTimeout < 0 || entries == null || values == null
|| values.length != entries.length) {
diff --git a/src/com/android/settings/gestures/PreventRingingGesturePreferenceController.java b/src/com/android/settings/gestures/PreventRingingGesturePreferenceController.java
index cb9bf4f..8f037ce 100644
--- a/src/com/android/settings/gestures/PreventRingingGesturePreferenceController.java
+++ b/src/com/android/settings/gestures/PreventRingingGesturePreferenceController.java
@@ -46,7 +46,7 @@
OnResume, OnPause, OnCreate, PreferenceControllerMixin {
@VisibleForTesting static final String KEY_VIBRATE = "prevent_ringing_option_vibrate";
- @VisibleForTesting static final String KEY_NONE = "prevent_ringing_option_none";
+
@VisibleForTesting static final String KEY_MUTE = "prevent_ringing_option_mute";
private final String KEY_VIDEO_PAUSED = "key_video_paused";
@@ -57,9 +57,8 @@
private VideoPreference mVideoPreference;
private boolean mVideoPaused;
- private PreferenceCategory mPreferenceCategory;
+ @VisibleForTesting PreferenceCategory mPreferenceCategory;
@VisibleForTesting RadioButtonPreference mVibratePref;
- @VisibleForTesting RadioButtonPreference mNonePref;
@VisibleForTesting RadioButtonPreference mMutePref;
private SettingObserver mSettingObserver;
@@ -80,7 +79,6 @@
mPreferenceCategory = (PreferenceCategory) screen.findPreference(getPreferenceKey());
mVibratePref = makeRadioPreference(KEY_VIBRATE, R.string.prevent_ringing_option_vibrate);
mMutePref = makeRadioPreference(KEY_MUTE, R.string.prevent_ringing_option_mute);
- mNonePref = makeRadioPreference(KEY_NONE, R.string.prevent_ringing_option_none);
if (mPreferenceCategory != null) {
mSettingObserver = new SettingObserver(mPreferenceCategory);
@@ -124,19 +122,21 @@
public void updateState(Preference preference) {
int preventRingingSetting = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.VOLUME_HUSH_GESTURE, Settings.Secure.VOLUME_HUSH_VIBRATE);
-
final boolean isVibrate = preventRingingSetting == Settings.Secure.VOLUME_HUSH_VIBRATE;
final boolean isMute = preventRingingSetting == Settings.Secure.VOLUME_HUSH_MUTE;
- final boolean isOff = preventRingingSetting == Settings.Secure.VOLUME_HUSH_OFF
- || (!isVibrate && !isMute);
if (mVibratePref != null && mVibratePref.isChecked() != isVibrate) {
mVibratePref.setChecked(isVibrate);
}
if (mMutePref != null && mMutePref.isChecked() != isMute) {
mMutePref.setChecked(isMute);
}
- if (mNonePref != null && mNonePref.isChecked() != isOff) {
- mNonePref.setChecked(isOff);
+
+ if (preventRingingSetting == Settings.Secure.VOLUME_HUSH_OFF) {
+ mVibratePref.setEnabled(false);
+ mMutePref.setEnabled(false);
+ } else {
+ mVibratePref.setEnabled(true);
+ mMutePref.setEnabled(true);
}
}
@@ -173,13 +173,12 @@
private int keyToSetting(String key) {
switch (key) {
- case KEY_NONE:
- return Settings.Secure.VOLUME_HUSH_OFF;
case KEY_MUTE:
return Settings.Secure.VOLUME_HUSH_MUTE;
case KEY_VIBRATE:
- default:
return Settings.Secure.VOLUME_HUSH_VIBRATE;
+ default:
+ return Settings.Secure.VOLUME_HUSH_OFF;
}
}
diff --git a/src/com/android/settings/gestures/PreventRingingGestureSettings.java b/src/com/android/settings/gestures/PreventRingingGestureSettings.java
index 3e8ae85..420a019 100644
--- a/src/com/android/settings/gestures/PreventRingingGestureSettings.java
+++ b/src/com/android/settings/gestures/PreventRingingGestureSettings.java
@@ -35,7 +35,6 @@
public class PreventRingingGestureSettings extends DashboardFragment {
private static final String TAG = "RingingGestureSettings";
- private static final String KEY_PREVENT_RINGING = "gesture_prevent_ringing";
@Override
public void onAttach(Context context) {
@@ -51,6 +50,7 @@
Lifecycle lifecycle) {
List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new PreventRingingGesturePreferenceController(context, lifecycle));
+ controllers.add(new PreventRingingSwitchPreferenceController(context));
return controllers;
}
diff --git a/src/com/android/settings/gestures/PreventRingingSwitchPreferenceController.java b/src/com/android/settings/gestures/PreventRingingSwitchPreferenceController.java
new file mode 100644
index 0000000..b94cfff
--- /dev/null
+++ b/src/com/android/settings/gestures/PreventRingingSwitchPreferenceController.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.gestures;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+import android.widget.Switch;
+
+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.settings.widget.SwitchBar;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.widget.LayoutPreference;
+
+public class PreventRingingSwitchPreferenceController extends AbstractPreferenceController
+ implements PreferenceControllerMixin, SwitchBar.OnSwitchChangeListener {
+
+ private static final String KEY = "gesture_prevent_ringing_switch";
+ private final Context mContext;
+ private SettingObserver mSettingObserver;
+
+ @VisibleForTesting SwitchBar mSwitch;
+
+ public PreventRingingSwitchPreferenceController(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ if (isAvailable()) {
+ LayoutPreference pref = (LayoutPreference) screen.findPreference(getPreferenceKey());
+ if (pref != null) {
+ mSettingObserver = new SettingObserver(pref);
+ mSwitch = pref.findViewById(R.id.switch_bar);
+ if (mSwitch != null) {
+ mSwitch.addOnSwitchChangeListener(this);
+ mSwitch.show();
+ }
+ }
+ }
+ }
+
+ public void setChecked(boolean isChecked) {
+ if (mSwitch != null) {
+ mSwitch.setChecked(isChecked);
+ }
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ int preventRingingSetting = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.VOLUME_HUSH_GESTURE, Settings.Secure.VOLUME_HUSH_VIBRATE);
+ setChecked(preventRingingSetting != Settings.Secure.VOLUME_HUSH_OFF);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_volumeHushGestureEnabled);
+ }
+
+ @Override
+ public void onSwitchChanged(Switch switchView, boolean isChecked) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.VOLUME_HUSH_GESTURE, isChecked ? Settings.Secure.VOLUME_HUSH_VIBRATE
+ : Settings.Secure.VOLUME_HUSH_OFF);
+ }
+
+ private class SettingObserver extends ContentObserver {
+ private final Uri VOLUME_HUSH_GESTURE = Settings.Secure.getUriFor(
+ Settings.Secure.VOLUME_HUSH_GESTURE);
+
+ private final Preference mPreference;
+
+ public SettingObserver(Preference preference) {
+ super(new Handler());
+ mPreference = preference;
+ }
+
+ public void register(ContentResolver cr) {
+ cr.registerContentObserver(VOLUME_HUSH_GESTURE, false, this);
+ }
+
+ public void unregister(ContentResolver cr) {
+ cr.unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ super.onChange(selfChange, uri);
+ if (uri == null || VOLUME_HUSH_GESTURE.equals(uri)) {
+ updateState(mPreference);
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index d3f11a0..d40006f 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -19,6 +19,7 @@
import android.content.Intent;
import android.os.Bundle;
import android.util.FeatureFlagUtils;
+import android.view.View;
import android.widget.ImageView;
import android.widget.Toolbar;
@@ -47,6 +48,7 @@
return;
}
+ updateWindowProperties();
setContentView(R.layout.settings_homepage_container);
final Toolbar toolbar = findViewById(R.id.search_action_bar);
@@ -73,4 +75,15 @@
}
fragmentTransaction.commit();
}
+
+ private void updateWindowProperties() {
+ final View decorView = getWindow().getDecorView();
+ decorView.setSystemUiVisibility(
+ decorView.getSystemUiVisibility() |
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ );
+
+ getWindow().setStatusBarColor(getResources().getColor(R.color.homepage_status_bar_color));
+ }
}
\ No newline at end of file
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
index 88478e3..49e2a76 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
@@ -107,12 +107,12 @@
}
}
}
- return getFinalDisplayableCards(result);
+ return getDisplayableCards(result);
}
// Get final displayed cards and log what cards will be displayed/hidden
@VisibleForTesting
- List<ContextualCard> getFinalDisplayableCards(List<ContextualCard> candidates) {
+ List<ContextualCard> getDisplayableCards(List<ContextualCard> candidates) {
final List<ContextualCard> eligibleCards = filterEligibleCards(candidates);
final List<ContextualCard> visibleCards = new ArrayList<>();
final List<ContextualCard> hiddenCards = new ArrayList<>();
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java
index a4a8419..90974f6 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java
@@ -84,7 +84,11 @@
LegacySuggestionContextualCardController.class,
LegacySuggestionContextualCardRenderer.class));
add(new ControllerRendererMapping(CardType.SLICE,
- SliceContextualCardRenderer.VIEW_TYPE,
+ SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH,
+ SliceContextualCardController.class,
+ SliceContextualCardRenderer.class));
+ add(new ControllerRendererMapping(CardType.SLICE,
+ SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH,
SliceContextualCardController.class,
SliceContextualCardRenderer.class));
add(new ControllerRendererMapping(CardType.CONDITIONAL_FOOTER,
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index 067de7c..12088f8 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -17,6 +17,7 @@
package com.android.settings.homepage.contextualcards;
import static com.android.settings.homepage.contextualcards.ContextualCardLoader.CARD_CONTENT_LOADER_ID;
+import static com.android.settings.intelligence.ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE;
import static java.util.stream.Collectors.groupingBy;
@@ -172,7 +173,8 @@
//replace with the new data
mContextualCards.clear();
- mContextualCards.addAll(sortCards(allCards));
+ final List<ContextualCard> sortedCards = sortCards(allCards);
+ mContextualCards.addAll(assignCardWidth(sortedCards));
loadCardControllers();
@@ -224,6 +226,24 @@
mListener = listener;
}
+ @VisibleForTesting
+ List<ContextualCard> assignCardWidth(List<ContextualCard> cards) {
+ final List<ContextualCard> result = new ArrayList<>(cards);
+ // Shows as half cards if 2 suggestion type of cards are next to each other.
+ // Shows as full card if 1 suggestion type of card lives alone.
+ for (int index = 1; index < result.size(); index++) {
+ final ContextualCard previous = result.get(index - 1);
+ final ContextualCard current = result.get(index);
+ if (current.getCategory() == SUGGESTION_VALUE
+ && previous.getCategory() == SUGGESTION_VALUE) {
+ result.set(index - 1, previous.mutate().setIsHalfWidth(true).build());
+ result.set(index, current.mutate().setIsHalfWidth(true).build());
+ index++;
+ }
+ }
+ return result;
+ }
+
private List<ContextualCard> getCardsToKeep(List<ContextualCard> cards) {
if (mSavedCards != null) {
//screen rotate
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardController.java b/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardController.java
index 834ebbc..b477d52 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardController.java
@@ -40,7 +40,7 @@
*/
public class ConditionContextualCardController implements ContextualCardController,
ConditionListener, LifecycleObserver, OnStart, OnStop {
- public static final int EXPANDING_THRESHOLD = 2;
+ public static final int EXPANDING_THRESHOLD = 0;
private static final double UNSUPPORTED_RANKING = -99999.0;
private static final String TAG = "ConditionCtxCardCtrl";
diff --git a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
index ab1b4c9..531501b 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
@@ -82,8 +82,8 @@
return buildBatteryGoodSlice(sliceBuilder, true);
}
- final List<BatteryTip> batteryTips = SliceBackgroundWorker.getInstance(mContext,
- this).getResults();
+ final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance(getUri());
+ final List<BatteryTip> batteryTips = worker != null ? worker.getResults() : null;
if (batteryTips == null) {
// Because we need wait slice background worker return data
diff --git a/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
index 6a75274..b2bec7f 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
@@ -273,7 +273,7 @@
private SliceAction buildBluetoothDetailDeepLinkAction(CachedBluetoothDevice bluetoothDevice) {
return SliceAction.createDeeplink(
getBluetoothDetailIntent(bluetoothDevice),
- IconCompat.createWithResource(mContext, R.drawable.ic_settings),
+ IconCompat.createWithResource(mContext, R.drawable.ic_settings_24dp),
ListBuilder.ICON_IMAGE,
bluetoothDevice.getName());
}
@@ -287,9 +287,7 @@
final CharSequence title = mContext.getText(R.string.bluetooth_pairing_pref_title);
final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.ic_menu_add);
final SliceAction sliceAction = SliceAction.createDeeplink(
- getPairNewDeviceIntent(),
- IconCompat.createWithResource(mContext, R.drawable.ic_settings),
- ListBuilder.ICON_IMAGE, title);
+ getPairNewDeviceIntent(), icon, ListBuilder.ICON_IMAGE, title);
return new ListBuilder.RowBuilder()
.setTitleItem(icon, ListBuilder.ICON_IMAGE)
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
index 7ca6e9a..5a43f66 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
@@ -26,7 +26,6 @@
import android.widget.Button;
import android.widget.ViewFlipper;
-import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
@@ -35,40 +34,40 @@
import androidx.lifecycle.OnLifecycleEvent;
import androidx.recyclerview.widget.RecyclerView;
import androidx.slice.Slice;
-import androidx.slice.SliceItem;
-import androidx.slice.widget.EventInfo;
import androidx.slice.widget.SliceLiveData;
-import androidx.slice.widget.SliceView;
import com.android.settings.R;
import com.android.settings.homepage.contextualcards.CardContentProvider;
import com.android.settings.homepage.contextualcards.ContextualCard;
-import com.android.settings.homepage.contextualcards.ContextualCardFeatureProvider;
import com.android.settings.homepage.contextualcards.ContextualCardRenderer;
import com.android.settings.homepage.contextualcards.ControllerRendererPool;
-import com.android.settings.overlay.FeatureFactory;
import java.util.Map;
import java.util.Set;
/**
- * Card renderer for {@link ContextualCard} built as slices.
+ * Card renderer for {@link ContextualCard} built as slice full card or slice half card.
*/
-public class SliceContextualCardRenderer implements ContextualCardRenderer,
- SliceView.OnSliceActionListener, LifecycleObserver {
- public static final int VIEW_TYPE = R.layout.homepage_slice_tile;
+public class SliceContextualCardRenderer implements ContextualCardRenderer, LifecycleObserver {
+ public static final int VIEW_TYPE_FULL_WIDTH = R.layout.homepage_slice_tile;
+ public static final int VIEW_TYPE_HALF_WIDTH = R.layout.homepage_slice_half_tile;
private static final String TAG = "SliceCardRenderer";
@VisibleForTesting
final Map<Uri, LiveData<Slice>> mSliceLiveDataMap;
@VisibleForTesting
- final Set<SliceViewHolder> mFlippedCardSet;
+ final Set<RecyclerView.ViewHolder> mFlippedCardSet;
private final Context mContext;
private final LifecycleOwner mLifecycleOwner;
private final ControllerRendererPool mControllerRendererPool;
private final Set<ContextualCard> mCardSet;
+ private final SliceFullCardRendererHelper mFullCardHelper;
+ private final SliceHalfCardRendererHelper mHalfCardHelper;
+
+ //TODO(b/121303357): Remove isHalfWidth field from SliceContextualCardRenderer class.
+ private boolean mIsHalfWidth;
public SliceContextualCardRenderer(Context context, LifecycleOwner lifecycleOwner,
ControllerRendererPool controllerRendererPool) {
@@ -79,21 +78,26 @@
mCardSet = new ArraySet<>();
mFlippedCardSet = new ArraySet<>();
mLifecycleOwner.getLifecycle().addObserver(this);
+ mFullCardHelper = new SliceFullCardRendererHelper(context);
+ mHalfCardHelper = new SliceHalfCardRendererHelper(context);
}
@Override
public int getViewType(boolean isHalfWidth) {
- return VIEW_TYPE;
+ mIsHalfWidth = isHalfWidth;
+ return isHalfWidth? VIEW_TYPE_HALF_WIDTH : VIEW_TYPE_FULL_WIDTH;
}
@Override
public RecyclerView.ViewHolder createViewHolder(View view) {
- return new SliceViewHolder(view);
+ if (mIsHalfWidth) {
+ return mHalfCardHelper.createViewHolder(view);
+ }
+ return mFullCardHelper.createViewHolder(view);
}
@Override
public void bindView(RecyclerView.ViewHolder holder, ContextualCard card) {
- final SliceViewHolder cardHolder = (SliceViewHolder) holder;
final Uri uri = card.getSliceUri();
//TODO(b/120629936): Take this out once blank card issue is fixed.
Log.d(TAG, "bindView - uri = " + uri);
@@ -103,10 +107,6 @@
return;
}
- cardHolder.sliceView.setScrollable(false);
- cardHolder.sliceView.setTag(uri);
- //TODO(b/114009676): We will soon have a field to decide what slice mode we should set.
- cardHolder.sliceView.setMode(SliceView.MODE_LARGE);
LiveData<Slice> sliceLiveData = mSliceLiveDataMap.get(uri);
if (sliceLiveData == null) {
@@ -125,82 +125,58 @@
//TODO(b/120629936): Take this out once blank card issue is fixed.
Log.d(TAG, "Slice callback - uri = " + slice.getUri());
}
- cardHolder.sliceView.setSlice(slice);
+ if (holder.getItemViewType() == VIEW_TYPE_HALF_WIDTH) {
+ mHalfCardHelper.bindView(holder, card, slice);
+ } else {
+ mFullCardHelper.bindView(holder, card, slice, mCardSet);
+ }
});
- // Set this listener so we can log the interaction users make on the slice
- cardHolder.sliceView.setOnSliceActionListener(this);
-
- // Customize slice view for Settings
- cardHolder.sliceView.showTitleItems(true);
- if (card.isLargeCard()) {
- cardHolder.sliceView.showHeaderDivider(true);
- cardHolder.sliceView.showActionDividers(true);
+ if (holder.getItemViewType() == VIEW_TYPE_HALF_WIDTH) {
+ initDismissalActions(holder, card, R.id.content);
+ } else {
+ initDismissalActions(holder, card, R.id.slice_view);
}
-
- initDismissalActions(cardHolder, card);
}
- private void initDismissalActions(SliceViewHolder cardHolder, ContextualCard card) {
- cardHolder.sliceView.setOnLongClickListener(v -> {
- cardHolder.viewFlipper.showNext();
- mFlippedCardSet.add(cardHolder);
+ private void initDismissalActions(RecyclerView.ViewHolder holder, ContextualCard card,
+ int initialViewId) {
+ // initialView is the first view in the ViewFlipper.
+ final View initialView = holder.itemView.findViewById(initialViewId);
+ initialView.setOnLongClickListener(v -> {
+ flipCardToDismissalView(holder);
+ mFlippedCardSet.add(holder);
return true;
});
- final Button btnKeep = cardHolder.itemView.findViewById(R.id.keep);
+ final Button btnKeep = holder.itemView.findViewById(R.id.keep);
btnKeep.setOnClickListener(v -> {
- cardHolder.resetCard();
- mFlippedCardSet.remove(cardHolder);
+ mFlippedCardSet.remove(holder);
+ resetCardView(holder);
});
- final Button btnRemove = cardHolder.itemView.findViewById(R.id.remove);
+ final Button btnRemove = holder.itemView.findViewById(R.id.remove);
btnRemove.setOnClickListener(v -> {
mControllerRendererPool.getController(mContext, card.getCardType()).onDismissed(card);
- cardHolder.resetCard();
- mFlippedCardSet.remove(cardHolder);
+ mFlippedCardSet.remove(holder);
+ resetCardView(holder);
mSliceLiveDataMap.get(card.getSliceUri()).removeObservers(mLifecycleOwner);
});
}
- @Override
- public void onSliceAction(@NonNull EventInfo eventInfo, @NonNull SliceItem sliceItem) {
- //TODO(b/79698338): Log user interaction
-
- // sliceItem.getSlice().getUri() is like
- // content://android.settings.slices/action/wifi/_gen/0/_gen/0
- // contextualCard.getSliceUri() is prefix of sliceItem.getSlice().getUri()
- for (ContextualCard card : mCardSet) {
- if (sliceItem.getSlice().getUri().toString().startsWith(
- card.getSliceUri().toString())) {
- ContextualCardFeatureProvider contexualCardFeatureProvider =
- FeatureFactory.getFactory(mContext)
- .getContextualCardFeatureProvider(mContext);
- contexualCardFeatureProvider.logContextualCardClick(card,
- eventInfo.rowIndex, eventInfo.actionType);
- break;
- }
- }
- }
-
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop() {
- mFlippedCardSet.stream().forEach(holder -> holder.resetCard());
+ mFlippedCardSet.stream().forEach(holder -> resetCardView(holder));
mFlippedCardSet.clear();
}
- public static class SliceViewHolder extends RecyclerView.ViewHolder {
- public final SliceView sliceView;
- public final ViewFlipper viewFlipper;
+ private void resetCardView(RecyclerView.ViewHolder holder) {
+ final ViewFlipper viewFlipper = holder.itemView.findViewById(R.id.view_flipper);
+ viewFlipper.setDisplayedChild(0 /* whichChild */);
+ }
- public SliceViewHolder(View view) {
- super(view);
- sliceView = view.findViewById(R.id.slice_view);
- viewFlipper = view.findViewById(R.id.view_flipper);
- }
-
- public void resetCard() {
- viewFlipper.setDisplayedChild(0);
- }
+ private void flipCardToDismissalView(RecyclerView.ViewHolder holder) {
+ final ViewFlipper viewFlipper = holder.itemView.findViewById(R.id.view_flipper);
+ viewFlipper.showNext();
}
}
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceFullCardRendererHelper.java b/src/com/android/settings/homepage/contextualcards/slices/SliceFullCardRendererHelper.java
new file mode 100644
index 0000000..ef0a67d
--- /dev/null
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceFullCardRendererHelper.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.homepage.contextualcards.slices;
+
+import android.content.Context;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+import androidx.slice.widget.EventInfo;
+import androidx.slice.widget.SliceView;
+
+import com.android.settings.R;
+import com.android.settings.homepage.contextualcards.ContextualCard;
+import com.android.settings.homepage.contextualcards.ContextualCardFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+
+import java.util.Set;
+
+/**
+ * Card renderer helper for {@link ContextualCard} built as slice full card.
+ */
+class SliceFullCardRendererHelper implements SliceView.OnSliceActionListener {
+ private static final String TAG = "SliceFCRendererHelper";
+
+ private final Context mContext;
+
+ private Set<ContextualCard> mCardSet;
+
+ SliceFullCardRendererHelper(Context context) {
+ mContext = context;
+ }
+
+ RecyclerView.ViewHolder createViewHolder(View view) {
+ return new SliceViewHolder(view);
+ }
+
+ void bindView(RecyclerView.ViewHolder holder, ContextualCard card, Slice slice,
+ Set<ContextualCard> cardSet) {
+ final SliceViewHolder cardHolder = (SliceViewHolder) holder;
+ cardHolder.sliceView.setScrollable(false);
+ cardHolder.sliceView.setTag(card.getSliceUri());
+ //TODO(b/114009676): We will soon have a field to decide what slice mode we should set.
+ cardHolder.sliceView.setMode(SliceView.MODE_LARGE);
+ cardHolder.sliceView.setSlice(slice);
+ mCardSet = cardSet;
+ // Set this listener so we can log the interaction users make on the slice
+ cardHolder.sliceView.setOnSliceActionListener(this);
+
+ // Customize slice view for Settings
+ cardHolder.sliceView.showTitleItems(true);
+ if (card.isLargeCard()) {
+ cardHolder.sliceView.showHeaderDivider(true);
+ cardHolder.sliceView.showActionDividers(true);
+ }
+ }
+
+ @Override
+ public void onSliceAction(@NonNull EventInfo eventInfo, @NonNull SliceItem sliceItem) {
+ // sliceItem.getSlice().getUri() is like
+ // content://android.settings.slices/action/wifi/_gen/0/_gen/0
+ // contextualCard.getSliceUri() is prefix of sliceItem.getSlice().getUri()
+ final ContextualCardFeatureProvider contextualCardFeatureProvider =
+ FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(mContext);
+ for (ContextualCard card : mCardSet) {
+ if (sliceItem.getSlice().getUri().toString().startsWith(
+ card.getSliceUri().toString())) {
+ contextualCardFeatureProvider.logContextualCardClick(card, eventInfo.rowIndex,
+ eventInfo.actionType);
+ break;
+ }
+ }
+ }
+
+ static class SliceViewHolder extends RecyclerView.ViewHolder {
+ public final SliceView sliceView;
+
+ public SliceViewHolder(View view) {
+ super(view);
+ sliceView = view.findViewById(R.id.slice_view);
+ }
+ }
+}
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceHalfCardRendererHelper.java b/src/com/android/settings/homepage/contextualcards/slices/SliceHalfCardRendererHelper.java
new file mode 100644
index 0000000..24d654d
--- /dev/null
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceHalfCardRendererHelper.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.homepage.contextualcards.slices;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.slice.Slice;
+import androidx.slice.SliceMetadata;
+import androidx.slice.core.SliceAction;
+import androidx.slice.widget.EventInfo;
+
+import com.android.settings.R;
+import com.android.settings.homepage.contextualcards.ContextualCard;
+import com.android.settings.homepage.contextualcards.ContextualCardFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+
+/**
+ * Card renderer helper for {@link ContextualCard} built as slice half card.
+ */
+class SliceHalfCardRendererHelper {
+ private static final String TAG = "SliceHCRendererHelper";
+
+ private final Context mContext;
+
+ SliceHalfCardRendererHelper(Context context) {
+ mContext = context;
+ }
+
+ RecyclerView.ViewHolder createViewHolder(View view) {
+ return new HalfCardViewHolder(view);
+ }
+
+ void bindView(RecyclerView.ViewHolder holder, ContextualCard card, Slice slice) {
+ final HalfCardViewHolder view = (HalfCardViewHolder) holder;
+ final SliceMetadata sliceMetadata = SliceMetadata.from(mContext, slice);
+ final SliceAction primaryAction = sliceMetadata.getPrimaryAction();
+ view.icon.setImageDrawable(primaryAction.getIcon().loadDrawable(mContext));
+ view.title.setText(primaryAction.getTitle());
+ view.content.setOnClickListener(v -> {
+ try {
+ primaryAction.getAction().send();
+ } catch (PendingIntent.CanceledException e) {
+ Log.w(TAG, "Failed to start intent " + primaryAction.getTitle());
+ }
+ final ContextualCardFeatureProvider contextualCardFeatureProvider =
+ FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(mContext);
+ contextualCardFeatureProvider.logContextualCardClick(card, 0 /* row */,
+ EventInfo.ACTION_TYPE_CONTENT);
+ });
+ }
+
+ static class HalfCardViewHolder extends RecyclerView.ViewHolder {
+ public final LinearLayout content;
+ public final ImageView icon;
+ public final TextView title;
+
+ public HalfCardViewHolder(View itemView) {
+ super(itemView);
+ content = itemView.findViewById(R.id.content);
+ icon = itemView.findViewById(android.R.id.icon);
+ title = itemView.findViewById(android.R.id.title);
+ }
+ }
+}
diff --git a/src/com/android/settings/location/AppLocationPermissionPreferenceController.java b/src/com/android/settings/location/AppLocationPermissionPreferenceController.java
index 5bfc584..1fd1986 100644
--- a/src/com/android/settings/location/AppLocationPermissionPreferenceController.java
+++ b/src/com/android/settings/location/AppLocationPermissionPreferenceController.java
@@ -6,9 +6,10 @@
import android.content.Context;
import android.location.LocationManager;
-import android.permission.RuntimePermissionPresenter;
+import android.permission.PermissionControllerManager;
import android.provider.Settings;
+import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import com.android.settings.R;
@@ -24,9 +25,11 @@
private static final String KEY_APP_LEVEL_PERMISSIONS = "app_level_permissions";
/** Total number of apps that has location permission. */
- private int mNumTotal = -1;
+ @VisibleForTesting
+ int mNumTotal = -1;
/** Total number of apps that has background location permission. */
- private int mNumBackground = -1;
+ @VisibleForTesting
+ int mNumBackground = -1;
private final LocationManager mLocationManager;
private Preference mPreference;
@@ -70,7 +73,9 @@
if (!mLocationManager.isLocationEnabled()) {
return;
}
- RuntimePermissionPresenter.getInstance(mContext).countPermissionApps(
+ PermissionControllerManager permController =
+ mContext.getSystemService(PermissionControllerManager.class);
+ permController.countPermissionApps(
Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION), false, false,
(numApps) -> {
mNumTotal = numApps;
@@ -79,7 +84,7 @@
}
}, null);
- RuntimePermissionPresenter.getInstance(mContext).countPermissionApps(
+ permController.countPermissionApps(
Collections.singletonList(ACCESS_BACKGROUND_LOCATION), true, false,
(numApps) -> {
mNumBackground = numApps;
diff --git a/src/com/android/settings/location/TopLevelLocationPreferenceController.java b/src/com/android/settings/location/TopLevelLocationPreferenceController.java
index 455af21..6d7789f 100644
--- a/src/com/android/settings/location/TopLevelLocationPreferenceController.java
+++ b/src/com/android/settings/location/TopLevelLocationPreferenceController.java
@@ -8,7 +8,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
-import android.permission.RuntimePermissionPresenter;
+import android.permission.PermissionControllerManager;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -70,7 +70,7 @@
if (!mLocationManager.isLocationEnabled()) {
return;
}
- RuntimePermissionPresenter.getInstance(mContext).countPermissionApps(
+ mContext.getSystemService(PermissionControllerManager.class).countPermissionApps(
Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION), false, false,
(numApps) -> {
setLocationAppCount(numApps);
diff --git a/src/com/android/settings/network/NetworkDashboardFragment.java b/src/com/android/settings/network/NetworkDashboardFragment.java
index 7d94bba..c2b4a2b 100644
--- a/src/com/android/settings/network/NetworkDashboardFragment.java
+++ b/src/com/android/settings/network/NetworkDashboardFragment.java
@@ -21,7 +21,6 @@
import android.app.Dialog;
import android.content.Context;
import android.provider.SearchIndexableResource;
-import android.util.FeatureFlagUtils;
import android.util.Log;
import androidx.appcompat.app.AlertDialog;
@@ -31,6 +30,7 @@
import com.android.settings.R;
import com.android.settings.core.FeatureFlags;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.development.featureflags.FeatureFlagPersistent;
import com.android.settings.network.MobilePlanPreferenceController.MobilePlanPreferenceHost;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.wifi.WifiMasterSwitchPreferenceController;
@@ -61,7 +61,7 @@
@Override
protected int getPreferenceScreenResId() {
- if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.NETWORK_INTERNET_V2)) {
+ if (FeatureFlagPersistent.isEnabled(getContext(), FeatureFlags.NETWORK_INTERNET_V2)) {
return R.xml.network_and_internet_v2;
} else {
return R.xml.network_and_internet;
@@ -72,7 +72,7 @@
public void onAttach(Context context) {
super.onAttach(context);
- if (FeatureFlagUtils.isEnabled(context, FeatureFlags.NETWORK_INTERNET_V2)) {
+ if (FeatureFlagPersistent.isEnabled(context, FeatureFlags.NETWORK_INTERNET_V2)) {
use(MultiNetworkHeaderController.class).init(getSettingsLifecycle());
}
use(AirplaneModePreferenceController.class).setFragment(this);
diff --git a/src/com/android/settings/network/telephony/MobileDataDialogFragment.java b/src/com/android/settings/network/telephony/MobileDataDialogFragment.java
index be2da04..276d1fb 100644
--- a/src/com/android/settings/network/telephony/MobileDataDialogFragment.java
+++ b/src/com/android/settings/network/telephony/MobileDataDialogFragment.java
@@ -17,6 +17,7 @@
package com.android.settings.network.telephony;
import android.app.Dialog;
+import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
@@ -109,8 +110,7 @@
@Override
public int getMetricsCategory() {
- //TODO(b/114749736): add metric id for this fragment
- return 0;
+ return SettingsEnums.MOBILE_DATA_DIALOG;
}
@Override
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index 623b6de..6e5dece 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -196,7 +196,6 @@
}
}
- //TODO(b/114749736): update search provider
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
diff --git a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java
index f60f927..0326f42 100644
--- a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java
+++ b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java
@@ -116,8 +116,6 @@
}
private int getPreferredNetworkModeSummaryResId(int NetworkMode) {
- //TODO(b/114749736): refactor it to "Preferred network mode: <Mode>", instead of building
- // string for each type...
switch (NetworkMode) {
case TelephonyManager.NETWORK_MODE_TDSCDMA_GSM_WCDMA:
return R.string.preferred_network_mode_tdscdma_gsm_wcdma_summary;
diff --git a/src/com/android/settings/network/telephony/RoamingDialogFragment.java b/src/com/android/settings/network/telephony/RoamingDialogFragment.java
index 4c82686..c349c1a 100644
--- a/src/com/android/settings/network/telephony/RoamingDialogFragment.java
+++ b/src/com/android/settings/network/telephony/RoamingDialogFragment.java
@@ -17,6 +17,7 @@
import android.app.AlertDialog;
import android.app.Dialog;
+import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
@@ -78,8 +79,7 @@
@Override
public int getMetricsCategory() {
- //TODO(b/114749736): add category for roaming dialog
- return 0;
+ return SettingsEnums.MOBILE_ROAMING_DIALOG;
}
@Override
diff --git a/src/com/android/settings/nfc/AndroidBeamPreferenceController.java b/src/com/android/settings/nfc/AndroidBeamPreferenceController.java
index 181faa5..b784dc5 100644
--- a/src/com/android/settings/nfc/AndroidBeamPreferenceController.java
+++ b/src/com/android/settings/nfc/AndroidBeamPreferenceController.java
@@ -16,6 +16,7 @@
package com.android.settings.nfc;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.nfc.NfcAdapter;
import androidx.preference.PreferenceScreen;
@@ -54,6 +55,10 @@
@Override
@AvailabilityStatus
public int getAvailabilityStatus() {
+ PackageManager pm = mContext.getPackageManager();
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_BEAM)) {
+ return UNSUPPORTED_ON_DEVICE;
+ }
return mNfcAdapter != null
? AVAILABLE
: UNSUPPORTED_ON_DEVICE;
diff --git a/src/com/android/settings/notification/NotificationStation.java b/src/com/android/settings/notification/NotificationStation.java
index d3ebc08..116980f 100644
--- a/src/com/android/settings/notification/NotificationStation.java
+++ b/src/com/android/settings/notification/NotificationStation.java
@@ -16,10 +16,13 @@
package com.android.settings.notification;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+
import android.app.Activity;
import android.app.ActivityManager;
import android.app.INotificationManager;
import android.app.Notification;
+import android.app.NotificationChannel;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -354,28 +357,53 @@
getString(R.string.notification_log_details_group_summary)));
}
}
- sb.append("\n")
- .append(bold(getString(R.string.notification_log_details_sound)))
- .append(delim);
- if (0 != (n.defaults & Notification.DEFAULT_SOUND)) {
- sb.append(getString(R.string.notification_log_details_default));
- } else if (n.sound != null) {
- sb.append(n.sound.toString());
- } else {
- sb.append(getString(R.string.notification_log_details_none));
- }
- sb.append("\n")
- .append(bold(getString(R.string.notification_log_details_vibrate)))
- .append(delim);
- if (0 != (n.defaults & Notification.DEFAULT_VIBRATE)) {
- sb.append(getString(R.string.notification_log_details_default));
- } else if (n.vibrate != null) {
- for (int vi=0;vi<n.vibrate.length;vi++) {
- if (vi > 0) sb.append(',');
- sb.append(String.valueOf(n.vibrate[vi]));
+ if (info.active) {
+ // mRanking only applies to active notifications
+ if (mRanking != null && mRanking.getRanking(sbn.getKey(), rank)) {
+ if (rank.getLastAudiblyAlertedMillis() > 0) {
+ sb.append("\n")
+ .append(bold(getString(R.string.notification_log_details_alerted)));
+ }
}
- } else {
- sb.append(getString(R.string.notification_log_details_none));
+ }
+ try {
+ NotificationChannel channel = mNoMan.getNotificationChannelForPackage(
+ sbn.getPackageName(), sbn.getUid(), n.getChannelId(), false);
+ sb.append("\n")
+ .append(bold(getString(R.string.notification_log_details_sound)))
+ .append(delim);
+ if (channel.getImportance() == IMPORTANCE_UNSPECIFIED) {
+
+ if (0 != (n.defaults & Notification.DEFAULT_SOUND)) {
+ sb.append(getString(R.string.notification_log_details_default));
+ } else if (n.sound != null) {
+ sb.append(n.sound.toString());
+ } else {
+ sb.append(getString(R.string.notification_log_details_none));
+ }
+ } else {
+ sb.append(String.valueOf(channel.getSound()));
+ }
+ sb.append("\n")
+ .append(bold(getString(R.string.notification_log_details_vibrate)))
+ .append(delim);
+ if (channel.getImportance() == IMPORTANCE_UNSPECIFIED) {
+ if (0 != (n.defaults & Notification.DEFAULT_VIBRATE)) {
+ sb.append(getString(R.string.notification_log_details_default));
+ } else if (n.vibrate != null) {
+ sb.append(getString(R.string.notification_log_details_vibrate_pattern));
+ } else {
+ sb.append(getString(R.string.notification_log_details_none));
+ }
+ } else {
+ if (channel.getVibrationPattern() != null) {
+ sb.append(getString(R.string.notification_log_details_vibrate_pattern));
+ } else {
+ sb.append(getString(R.string.notification_log_details_none));
+ }
+ }
+ } catch (RemoteException e) {
+ Log.d(TAG, "cannot read channel info", e);
}
sb.append("\n")
.append(bold(getString(R.string.notification_log_details_visibility)))
diff --git a/src/com/android/settings/slices/SliceBackgroundWorker.java b/src/com/android/settings/slices/SliceBackgroundWorker.java
index 8b68f05..284fd23 100644
--- a/src/com/android/settings/slices/SliceBackgroundWorker.java
+++ b/src/com/android/settings/slices/SliceBackgroundWorker.java
@@ -17,6 +17,7 @@
package com.android.settings.slices;
import android.annotation.MainThread;
+import android.annotation.Nullable;
import android.content.Context;
import android.net.Uri;
import android.util.ArrayMap;
@@ -58,20 +59,29 @@
mUri = uri;
}
- public Uri getUri() {
+ protected Uri getUri() {
return mUri;
}
/**
+ * Returns the singleton instance of the {@link SliceBackgroundWorker} for specified {@link Uri}
+ * if exists
+ */
+ @Nullable
+ public static SliceBackgroundWorker getInstance(Uri uri) {
+ return LIVE_WORKERS.get(uri);
+ }
+
+ /**
* Returns the singleton instance of the {@link SliceBackgroundWorker} for specified {@link
* CustomSliceable}
*/
- public static SliceBackgroundWorker getInstance(Context context, CustomSliceable sliceable) {
+ static SliceBackgroundWorker getInstance(Context context, CustomSliceable sliceable) {
final Uri uri = sliceable.getUri();
- final Class<? extends SliceBackgroundWorker> workerClass =
- sliceable.getBackgroundWorkerClass();
- SliceBackgroundWorker worker = LIVE_WORKERS.get(uri);
+ SliceBackgroundWorker worker = getInstance(uri);
if (worker == null) {
+ final Class<? extends SliceBackgroundWorker> workerClass =
+ sliceable.getBackgroundWorkerClass();
worker = createInstance(context, uri, workerClass);
LIVE_WORKERS.put(uri, worker);
}
diff --git a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
index 7a1bdb4..06e36e5 100644
--- a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
+++ b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
@@ -16,7 +16,6 @@
package com.android.settings.wifi;
-import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
@@ -67,9 +66,15 @@
/** Message sent to us to stop scanning wifi and pop up timeout dialog. */
private static final int MESSAGE_STOP_SCAN_WIFI_LIST = 0;
+ /** Message sent to us to finish activity. */
+ private static final int MESSAGE_FINISH_ACTIVITY = 1;
+
/** Spec defines there should be 5 wifi ap on the list at most. */
private static final int MAX_NUMBER_LIST_ITEM = 5;
+ /** Holding time to let user be aware that selected wifi ap is connected */
+ private static final int DELAY_TIME_USER_AWARE_CONNECTED_MS = 1 * 1000;
+
/** Delayed time to stop scanning wifi. */
private static final int DELAY_TIME_STOP_SCAN_MS = 30 * 1000;
@@ -155,7 +160,9 @@
public void onCancel(@NonNull DialogInterface dialog) {
super.onCancel(dialog);
// Finishes the activity when user clicks back key or outside of the dialog.
- getActivity().finish();
+ if (getActivity() != null) {
+ getActivity().finish();
+ }
}
@Override
@@ -177,6 +184,8 @@
@Override
public void onDestroy() {
super.onDestroy();
+
+ mHandler.removeMessages(MESSAGE_FINISH_ACTIVITY);
if (mFilterWifiTracker != null) {
mFilterWifiTracker.onDestroy();
mFilterWifiTracker = null;
@@ -207,7 +216,10 @@
switch (msg.what) {
case MESSAGE_STOP_SCAN_WIFI_LIST:
removeMessages(MESSAGE_STOP_SCAN_WIFI_LIST);
- stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE.TIME_OUT);
+ stopScanningAndMaybePopErrorDialog(ERROR_DIALOG_TYPE.TIME_OUT);
+ break;
+ case MESSAGE_FINISH_ACTIVITY:
+ stopScanningAndMaybePopErrorDialog(/* ERROR_DIALOG_TYPE */ null);
break;
default:
// Do nothing.
@@ -216,18 +228,29 @@
}
};
- protected void stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE type) {
+ protected void stopScanningAndMaybePopErrorDialog(ERROR_DIALOG_TYPE type) {
// Dismisses current dialog.
- dismiss();
+ final Dialog dialog = getDialog();
+ if (dialog != null && dialog.isShowing()) {
+ dismiss();
+ }
- // Throws new timeout dialog.
- final NetworkRequestErrorDialogFragment fragment = NetworkRequestErrorDialogFragment
- .newInstance();
- final Bundle bundle = new Bundle();
- bundle.putSerializable(NetworkRequestErrorDialogFragment.DIALOG_TYPE, type);
- fragment.setArguments(bundle);
- fragment.show(getActivity().getSupportFragmentManager(),
- NetworkRequestDialogFragment.class.getSimpleName());
+ if (type == null) {
+ // If no error, finishes activity.
+ if (getActivity() != null) {
+ getActivity().finish();
+ }
+ } else {
+ // Throws error dialog.
+ final NetworkRequestErrorDialogFragment fragment = NetworkRequestErrorDialogFragment
+ .newInstance();
+ final Bundle bundle = new Bundle();
+ bundle.putSerializable(NetworkRequestErrorDialogFragment.DIALOG_TYPE, type);
+ fragment.setArguments(bundle);
+ fragment.show(getActivity().getSupportFragmentManager(),
+ NetworkRequestDialogFragment.class.getSimpleName());
+ }
+
}
@Override
@@ -284,7 +307,7 @@
@Override
public void onAbort() {
- stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE.ABORT);
+ stopScanningAndMaybePopErrorDialog(ERROR_DIALOG_TYPE.ABORT);
}
@Override
@@ -295,10 +318,13 @@
@Override
public void onMatch(List<ScanResult> scanResults) {
- mHandler.removeMessages(MESSAGE_STOP_SCAN_WIFI_LIST);
- renewAccessPointList(scanResults);
+ // Shouldn't need to renew cached list, since input result is empty.
+ if (scanResults != null && scanResults.size() > 0) {
+ mHandler.removeMessages(MESSAGE_STOP_SCAN_WIFI_LIST);
+ renewAccessPointList(scanResults);
- notifyAdapterRefresh();
+ notifyAdapterRefresh();
+ }
}
// Updates internal AccessPoint list from WifiTracker. scanResults are used to update key list
@@ -329,17 +355,24 @@
@Override
public void onUserSelectionConnectSuccess(WifiConfiguration wificonfiguration) {
- // Dismisses current dialog and finishes Activity, since connection is success.
- dismiss();
- final Activity activity = getActivity();
- if (activity != null) {
- activity.finish();
+ // Removes the progress icon.
+ final Dialog dialog = getDialog();
+ if (dialog != null) {
+ final View view = dialog.findViewById(R.id.network_request_title_progress);
+ if (view != null) {
+ view.setVisibility(View.GONE);
+ }
}
+
+ // Posts delay to finish self since connection is success.
+ mHandler.removeMessages(MESSAGE_STOP_SCAN_WIFI_LIST);
+ mHandler.sendEmptyMessageDelayed(MESSAGE_FINISH_ACTIVITY,
+ DELAY_TIME_USER_AWARE_CONNECTED_MS);
}
@Override
public void onUserSelectionConnectFailure(WifiConfiguration wificonfiguration) {
- stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE.ABORT);
+ stopScanningAndMaybePopErrorDialog(ERROR_DIALOG_TYPE.ABORT);
}
private final class FilterWifiTracker {
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 95e912d..eddae06 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -240,7 +240,7 @@
mAddPreference.setIcon(R.drawable.ic_menu_add);
mAddPreference.setTitle(R.string.wifi_add_network);
if (WifiDppUtils.isSharingNetworkEnabled(getContext())) {
- mAddPreference.setButtonIcon(R.drawable.ic_qrcode_24dp);
+ mAddPreference.setButtonIcon(R.drawable.ic_scan_24dp);
mAddPreference.setButtonOnClickListener((View v) -> {
// Launch QR code scanner to join a network.
getContext().startActivity(
diff --git a/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java b/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
index 90fb850..8fa58f3 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
@@ -16,7 +16,12 @@
package com.android.settings.wifi.dpp;
+import android.app.ActionBar;
+import android.app.Activity;
+import android.content.Context;
+import android.net.wifi.WifiManager;
import android.os.Bundle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -33,18 +38,58 @@
* to the Wi-Fi network.
*/
public class WifiDppAddDeviceFragment extends WifiDppQrCodeBaseFragment {
- private ProgressBar mProgressBar;
+ private static final String TAG = "WifiDppAddDeviceFragment";
+
private ImageView mWifiApPictureView;
private TextView mChooseDifferentNetwork;
private Button mButtonLeft;
private Button mButtonRight;
+ private class DppStatusCallback extends android.net.wifi.DppStatusCallback {
+ @Override
+ public void onEnrolleeSuccess(int newNetworkId) {
+ // Do nothing
+ }
+
+ @Override
+ public void onConfiguratorSuccess(int code) {
+ // Update success UI.
+ mTitle.setText(R.string.wifi_dpp_wifi_shared_with_device);
+ mSummary.setVisibility(View.INVISIBLE);
+ mButtonLeft.setText(R.string.wifi_dpp_add_another_device);
+ mButtonLeft.setOnClickListener(v -> getFragmentManager().popBackStack());
+ mButtonRight.setText(R.string.done);
+ mButtonRight.setOnClickListener(v -> getActivity().finish());
+ }
+
+ @Override
+ public void onFailure(int code) {
+ //TODO(b/122429170): Show DPP configuration error state UI
+ Log.d(TAG, "DppStatusCallback.onFailure " + code);
+ }
+
+ @Override
+ public void onProgress(int code) {
+ // Do nothing
+ }
+ }
+
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
}
@Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ final ActionBar actionBar = getActivity().getActionBar();
+ if (actionBar != null) {
+ actionBar.hide();
+ }
+ }
+
+ @Override
public final View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.wifi_dpp_add_device_fragment, container,
@@ -55,10 +100,31 @@
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- mProgressBar = view.findViewById(R.id.progress_bar);
+ final WifiNetworkConfig wifiNetworkConfig = ((WifiDppConfiguratorActivity) getActivity())
+ .getWifiNetworkConfig();
+ if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
+ throw new IllegalStateException("Invalid Wi-Fi network for configuring");
+ }
+ mSummary.setText(getString(R.string.wifi_dpp_add_device_to_wifi,
+ wifiNetworkConfig.getSsid()));
+
mWifiApPictureView = view.findViewById(R.id.wifi_ap_picture_view);
mChooseDifferentNetwork = view.findViewById(R.id.choose_different_network);
mButtonLeft = view.findViewById(R.id.button_left);
+ mButtonLeft.setText(R.string.cancel);
+ mButtonLeft.setOnClickListener(v -> getFragmentManager().popBackStack());
+
mButtonRight = view.findViewById(R.id.button_right);
+ mButtonRight.setText(R.string.wifi_dpp_share_wifi);
+ mButtonRight.setOnClickListener(v -> startWifiDppInitiator());
+ }
+
+ private void startWifiDppInitiator() {
+ final String enrolleeUri = ((WifiDppConfiguratorActivity) getActivity()).getDppUri();
+ final int networkId =
+ ((WifiDppConfiguratorActivity) getActivity()).getWifiNetworkConfig().getNetworkId();
+ final WifiManager wifiManager = getContext().getSystemService(WifiManager.class);
+ wifiManager.startDppAsConfiguratorInitiator(enrolleeUri, networkId,
+ WifiManager.DPP_NETWORK_ROLE_STA, /* handler */ null, new DppStatusCallback());
}
}
diff --git a/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java b/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
index a3e6db3..8037e23 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
@@ -16,6 +16,8 @@
package com.android.settings.wifi.dpp;
+import android.app.ActionBar;
+import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -41,6 +43,16 @@
}
@Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ final ActionBar actionBar = getActivity().getActionBar();
+ if (actionBar != null) {
+ actionBar.hide();
+ }
+ }
+
+ @Override
public final View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.wifi_dpp_choose_saved_wifi_network_fragment, container,
@@ -51,8 +63,18 @@
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- mSavedWifiNetworkList = view.findViewById(R.id.saved_wifi_network_list);
+ mTitle.setText(R.string.wifi_dpp_choose_network);
+ mSummary.setText(R.string.wifi_dpp_choose_network_to_connect_device);
+
mButtonLeft = view.findViewById(R.id.button_left);
+ mButtonLeft.setText(R.string.cancel);
+ mButtonLeft.setOnClickListener(v -> {
+ Activity activity = getActivity();
+ activity.setResult(Activity.RESULT_CANCELED);
+ activity.finish();
+ });
+
mButtonRight = view.findViewById(R.id.button_right);
+ mButtonRight.setVisibility(View.GONE);
}
}
diff --git a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
index e89ebaa..b08546c 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
@@ -44,7 +44,7 @@
* {@code WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY}
* {@code WifiDppUtils.EXTRA_WIFI_HIDDEN_SSID}
*
- * For intent action {@code ACTION_CONFIGURATOR_CHOOSE_SAVED_WIFI_NETWORK}, specify Wi-Fi (DPP)
+ * For intent action {@code ACTION_PROCESS_WIFI_DPP_QR_CODE}, specify Wi-Fi (DPP)
* QR code in {@code WifiDppUtils.EXTRA_QR_CODE}
*/
public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
@@ -58,19 +58,19 @@
"android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_SCANNER";
public static final String ACTION_CONFIGURATOR_QR_CODE_GENERATOR =
"android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_GENERATOR";
- public static final String ACTION_CONFIGURATOR_CHOOSE_SAVED_WIFI_NETWORK =
- "android.settings.WIFI_DPP_CONFIGURATOR_CHOOSE_SAVED_WIFI_NETWORK";
+ public static final String ACTION_PROCESS_WIFI_DPP_QR_CODE =
+ "android.settings.PROCESS_WIFI_DPP_QR_CODE";
private FragmentManager mFragmentManager;
/** The Wi-Fi network which will be configured */
private WifiNetworkConfig mWifiNetworkConfig;
- /** The public key from Wi-Fi DPP QR code */
- private String mPublicKey;
+ /** The uri from Wi-Fi DPP QR code */
+ private String mDppUri;
- /** The information from Wi-Fi DPP QR code */
- private String mInformation;
+ /** The Wi-Fi DPP QR code from intent ACTION_PROCESS_WIFI_DPP_QR_CODE */
+ private WifiQrCode mWifiDppQrCode;
@Override
public int getMetricsCategory() {
@@ -115,8 +115,14 @@
showQrCodeGeneratorFragment();
}
break;
- case ACTION_CONFIGURATOR_CHOOSE_SAVED_WIFI_NETWORK:
- showChooseSavedWifiNetworkFragment(/* addToBackStack */ false);
+ case ACTION_PROCESS_WIFI_DPP_QR_CODE:
+ String qrCode = intent.getStringExtra(WifiDppUtils.EXTRA_QR_CODE);
+ mWifiDppQrCode = getValidWiFiDppQrCodeOrNull(qrCode);
+ if (mWifiDppQrCode == null) {
+ cancelActivity = true;
+ } else {
+ showChooseSavedWifiNetworkFragment(/* addToBackStack */ false);
+ }
break;
default:
cancelActivity = true;
@@ -199,17 +205,32 @@
fragmentTransaction.commit();
}
+ private WifiQrCode getValidWiFiDppQrCodeOrNull(String qrCode) {
+ WifiQrCode wifiQrCode;
+ try {
+ wifiQrCode = new WifiQrCode(qrCode);
+ } catch(IllegalArgumentException e) {
+ return null;
+ }
+
+ if (WifiQrCode.SCHEME_DPP.equals(wifiQrCode.getScheme())) {
+ return wifiQrCode;
+ }
+
+ return null;
+ }
+
@Override
public WifiNetworkConfig getWifiNetworkConfig() {
return mWifiNetworkConfig;
}
- public String getPublicKey() {
- return mPublicKey;
+ public String getDppUri() {
+ return mDppUri;
}
- public String getInformation() {
- return mInformation;
+ public WifiQrCode getWifiDppQrCode() {
+ return mWifiDppQrCode;
}
@Override
@@ -223,7 +244,7 @@
}
@Override
- public boolean onNavigateUp(){
+ public boolean onNavigateUp() {
Fragment fragment = mFragmentManager.findFragmentById(R.id.fragment_container);
if (fragment instanceof WifiDppQrCodeGeneratorFragment) {
setResult(Activity.RESULT_CANCELED);
@@ -242,18 +263,15 @@
}
@Override
- public void onScanWifiDppSuccess(String publicKey, String information) {
- mPublicKey = publicKey;
- mInformation = information;
- mWifiNetworkConfig = null;
+ public void onScanWifiDppSuccess(String uri) {
+ mDppUri = uri;
showAddDeviceFragment(/* addToBackStack */ true);
}
@Override
public void onScanZxingWifiFormatSuccess(WifiNetworkConfig wifiNetworkConfig) {
- mPublicKey = null;
- mInformation = null;
+ mDppUri = null;
mWifiNetworkConfig = new WifiNetworkConfig(wifiNetworkConfig);
showAddDeviceFragment(/* addToBackStack */ true);
diff --git a/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java b/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java
index 584a819..8c0e1f0 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java
@@ -16,6 +16,8 @@
package com.android.settings.wifi.dpp;
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
import android.provider.Settings;
import android.app.ActionBar;
import android.app.Activity;
@@ -32,6 +34,8 @@
import com.android.settings.core.InstrumentedActivity;
import com.android.settings.R;
+import java.util.List;
+
/**
* To provision "this" device with specified Wi-Fi network.
*
@@ -49,6 +53,39 @@
private FragmentManager mFragmentManager;
+ private class DppStatusCallback extends android.net.wifi.DppStatusCallback {
+ @Override
+ public void onEnrolleeSuccess(int newNetworkId) {
+ // Connect to the new network.
+ final WifiManager wifiManager = getSystemService(WifiManager.class);
+ final List<WifiConfiguration> wifiConfigs = wifiManager.getPrivilegedConfiguredNetworks();
+ for (WifiConfiguration wifiConfig : wifiConfigs) {
+ if (wifiConfig.networkId == newNetworkId) {
+ wifiManager.connect(wifiConfig, WifiDppEnrolleeActivity.this);
+ return;
+ }
+ }
+ Log.e(TAG, "Invalid networkId " + newNetworkId);
+ WifiDppEnrolleeActivity.this.onFailure(WifiManager.ERROR_AUTHENTICATING);
+ }
+
+ @Override
+ public void onConfiguratorSuccess(int code) {
+ // Do nothing
+ }
+
+ @Override
+ public void onFailure(int code) {
+ //TODO(b/122429170): Show DPP enrollee error state UI
+ Log.d(TAG, "DppStatusCallback.onFailure " + code);
+ }
+
+ @Override
+ public void onProgress(int code) {
+ // Do nothing
+ }
+ }
+
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_ENROLLEE;
@@ -108,8 +145,9 @@
}
@Override
- public void onScanWifiDppSuccess(String publicKey, String information) {
- // TODO(b/1023597): starts DPP enrollee handshake here
+ public void onScanWifiDppSuccess(String uri) {
+ final WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+ wifiManager.startDppAsEnrolleeInitiator(uri, /* handler */ null, new DppStatusCallback());
}
@Override
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
index c7c1461..2f59e18 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
@@ -62,9 +62,8 @@
private static final long SHOW_ERROR_MESSAGE_INTERVAL = 2000;
private static final long SHOW_SUCCESS_SQUARE_INTERVAL = 1000;
- // Keys for Bundle usage
- private static final String KEY_PUBLIC_KEY = "key_public_key";
- private static final String KEY_INFORMATION = "key_information";
+ // Key for Bundle usage
+ private static final String KEY_PUBLIC_URI = "key_public_uri";
private QrCamera mCamera;
private TextureView mTextureView;
@@ -91,7 +90,7 @@
// Container Activity must implement this interface
public interface OnScanWifiDppSuccessListener {
- public void onScanWifiDppSuccess(String publicKey, String information);
+ public void onScanWifiDppSuccess(String uri);
}
OnScanWifiDppSuccessListener mScanWifiDppSuccessListener;
@@ -269,7 +268,7 @@
public void handleSuccessfulResult(String qrCode) {
switch (mWifiQrCode.getScheme()) {
case WifiQrCode.SCHEME_DPP:
- handleWifiDpp(mWifiQrCode.getPublicKey(), mWifiQrCode.getInformation());
+ handleWifiDpp(qrCode);
break;
case WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG:
@@ -281,13 +280,12 @@
}
}
- private void handleWifiDpp(String publicKey, String information) {
+ private void handleWifiDpp(String uri) {
destroyCamera();
mDecorateView.setFocused(true);
final Bundle bundle = new Bundle();
- bundle.putString(KEY_PUBLIC_KEY, publicKey);
- bundle.putString(KEY_INFORMATION, information);
+ bundle.putString(KEY_PUBLIC_URI, uri);
Message message = mHandler.obtainMessage(MESSAGE_SCAN_WIFI_DPP_SUCCESS);
message.setData(bundle);
@@ -352,10 +350,9 @@
return;
}
final Bundle bundle = msg.getData();
- final String publicKey = bundle.getString(KEY_PUBLIC_KEY);
- final String information = bundle.getString(KEY_INFORMATION);
+ final String uri = bundle.getString(KEY_PUBLIC_URI);
- mScanWifiDppSuccessListener.onScanWifiDppSuccess(publicKey, information);
+ mScanWifiDppSuccessListener.onScanWifiDppSuccess(uri);
break;
case MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS:
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index 3a40e25..0205ec1 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -64,6 +64,9 @@
/** The data corresponding to {@code WifiConfiguration} hiddenSSID */
public static final String EXTRA_WIFI_HIDDEN_SSID = "hiddenSsid";
+ /** The data corresponding to {@code WifiConfiguration} networkId */
+ public static final String EXTRA_WIFI_NETWORK_ID = "networkId";
+
/** @see WifiQrCode */
public static final String EXTRA_QR_CODE = "qrCode";
@@ -164,6 +167,11 @@
if (!TextUtils.isEmpty(preSharedKey)) {
intent.putExtra(EXTRA_WIFI_PRE_SHARED_KEY, preSharedKey);
}
+ if (wifiConfig.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
+ throw new IllegalArgumentException("Invalid network ID");
+ } else {
+ intent.putExtra(EXTRA_WIFI_NETWORK_ID, wifiConfig.networkId);
+ }
return intent;
}
diff --git a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
index c9bfbd6..a9e88a9 100644
--- a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
+++ b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
@@ -46,13 +46,15 @@
private String mSsid;
private String mPreSharedKey;
private boolean mHiddenSsid;
+ private int mNetworkId;
- private WifiNetworkConfig(String security, String ssid, String preSharedKey,
- boolean hiddenSsid) {
+ private WifiNetworkConfig(String security, String ssid, String preSharedKey, boolean hiddenSsid,
+ int networkId) {
mSecurity = security;
mSsid = ssid;
mPreSharedKey = preSharedKey;
mHiddenSsid = hiddenSsid;
+ mNetworkId = networkId;
}
public WifiNetworkConfig(WifiNetworkConfig config) {
@@ -60,6 +62,7 @@
mSsid = config.mSsid;
mPreSharedKey = config.mPreSharedKey;
mHiddenSsid = config.mHiddenSsid;
+ mNetworkId = config.mNetworkId;
}
/**
@@ -82,17 +85,19 @@
String ssid = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_SSID);
String preSharedKey = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY);
boolean hiddenSsid = intent.getBooleanExtra(WifiDppUtils.EXTRA_WIFI_HIDDEN_SSID, false);
+ int networkId = intent.getIntExtra(WifiDppUtils.EXTRA_WIFI_NETWORK_ID,
+ WifiConfiguration.INVALID_NETWORK_ID);
- return getValidConfigOrNull(security, ssid, preSharedKey, hiddenSsid);
+ return getValidConfigOrNull(security, ssid, preSharedKey, hiddenSsid, networkId);
}
public static WifiNetworkConfig getValidConfigOrNull(String security, String ssid,
- String preSharedKey, boolean hiddenSsid) {
+ String preSharedKey, boolean hiddenSsid, int networkId) {
if (!isValidConfig(security, ssid, preSharedKey, hiddenSsid)) {
return null;
}
- return new WifiNetworkConfig(security, ssid, preSharedKey, hiddenSsid);
+ return new WifiNetworkConfig(security, ssid, preSharedKey, hiddenSsid, networkId);
}
public static boolean isValidConfig(WifiNetworkConfig config) {
@@ -184,6 +189,11 @@
return mHiddenSsid;
}
+ @Keep
+ public int getNetworkId() {
+ return mNetworkId;
+ }
+
public void connect(Context context, WifiManager.ActionListener listener) {
WifiConfiguration wifiConfiguration = getWifiConfigurationOrNull();
if (wifiConfiguration == null) {
@@ -208,6 +218,7 @@
final WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.SSID = addQuotationIfNeeded(mSsid);
wifiConfiguration.hiddenSSID = mHiddenSsid;
+ wifiConfiguration.networkId = mNetworkId;
if (TextUtils.isEmpty(mSecurity) || SECURITY_NO_PASSWORD.equals(mSecurity)) {
wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
diff --git a/src/com/android/settings/wifi/dpp/WifiQrCode.java b/src/com/android/settings/wifi/dpp/WifiQrCode.java
index a8562bb..8eae3a4 100644
--- a/src/com/android/settings/wifi/dpp/WifiQrCode.java
+++ b/src/com/android/settings/wifi/dpp/WifiQrCode.java
@@ -17,6 +17,7 @@
package com.android.settings.wifi.dpp;
import android.content.Intent;
+import android.net.wifi.WifiConfiguration;
import android.text.TextUtils;
import androidx.annotation.Keep;
@@ -135,7 +136,7 @@
password = removeBackSlash(password);
mWifiNetworkConfig = WifiNetworkConfig.getValidConfigOrNull(security, ssid, password,
- hiddenSsid);
+ hiddenSsid, WifiConfiguration.INVALID_NETWORK_ID);
if (mWifiNetworkConfig == null) {
throw new IllegalArgumentException("Invalid format");
diff --git a/src/com/android/settings/wifi/slice/WifiSlice.java b/src/com/android/settings/wifi/slice/WifiSlice.java
index 4d3a95a..35bb89f 100644
--- a/src/com/android/settings/wifi/slice/WifiSlice.java
+++ b/src/com/android/settings/wifi/slice/WifiSlice.java
@@ -105,8 +105,8 @@
return listBuilder.build();
}
- final List<AccessPoint> results =
- SliceBackgroundWorker.getInstance(mContext, this).getResults();
+ final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance(getUri());
+ final List<AccessPoint> results = worker != null ? worker.getResults() : null;
// Need a loading text when results are not ready.
boolean needLoadingRow = results == null;
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
index fb2ce97..c0a3fa7 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
@@ -53,10 +53,8 @@
final WifiConfiguration config = mWifiManager.getWifiApConfiguration();
if (config != null) {
mSSID = config.SSID;
- Log.d(TAG, "Updating SSID in Preference, " + mSSID);
} else {
mSSID = DEFAULT_SSID;
- Log.d(TAG, "Updating to default SSID in Preference, " + mSSID);
}
((ValidatedEditTextPreference) mPreference).setValidator(this);
updateSsidDisplay((EditTextPreference) mPreference);
diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml
index 101a6b8..59028d3 100644
--- a/tests/robotests/res/values-mcc999/config.xml
+++ b/tests/robotests/res/values-mcc999/config.xml
@@ -88,4 +88,7 @@
<!-- Email address for the homepage contextual cards feedback -->
<string name="config_contextual_card_feedback_email" translatable="false">test@test.test</string>
+
+ <!-- Max allowed value for screen timeout, in milliseconds -->
+ <integer name="max_lock_after_timeout_ms">1700000</integer>
</resources>
diff --git a/tests/robotests/src/com/android/settings/display/TimeoutListPreferenceTest.java b/tests/robotests/src/com/android/settings/display/TimeoutListPreferenceTest.java
index 55fcdac..7b67f0f 100644
--- a/tests/robotests/src/com/android/settings/display/TimeoutListPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/display/TimeoutListPreferenceTest.java
@@ -17,11 +17,11 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
import static org.robolectric.RuntimeEnvironment.application;
import android.util.AttributeSet;
+import com.android.settings.R;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settingslib.RestrictedLockUtils;
@@ -69,4 +69,23 @@
// should set to largest allowed value, which is 5 minute
assertThat(mPreference.getValue()).isEqualTo("300000");
}
+
+ @Test
+ @Config(qualifiers = "mcc999")
+ public void newInstance_hasLowTimeoutConfig_shouldRemoveLongTimeouts() {
+ final AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
+ final TimeoutListPreference pref = new TimeoutListPreference(application, attributeSet);
+ final long maxTimeout = application.getResources().getInteger(
+ R.integer.max_lock_after_timeout_ms);
+ pref.setEntries(R.array.screen_timeout_entries);
+ pref.setEntryValues(R.array.screen_timeout_values);
+
+ pref.updateInitialValues();
+
+ final CharSequence[] values = pref.getEntryValues();
+ for (CharSequence value : values) {
+ long timeout = Long.parseLong(value.toString());
+ assertThat(timeout).isAtMost(maxTimeout);
+ }
+ }
}
diff --git a/tests/robotests/src/com/android/settings/gestures/PreventRingingGesturePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/PreventRingingGesturePreferenceControllerTest.java
index 84fef5d..956d8bf 100644
--- a/tests/robotests/src/com/android/settings/gestures/PreventRingingGesturePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/gestures/PreventRingingGesturePreferenceControllerTest.java
@@ -18,44 +18,47 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
-import static org.mockito.MockitoAnnotations.initMocks;
import android.content.Context;
import android.content.res.Resources;
-import android.preference.PreferenceCategory;
import android.provider.Settings;
-import androidx.preference.PreferenceScreen;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
import com.android.settings.widget.RadioButtonPreference;
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 PreventRingingGesturePreferenceControllerTest {
-
private Context mContext;
private Resources mResources;
private PreventRingingGesturePreferenceController mController;
+ @Mock
+ private Preference mPreference;
+
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mResources = mock(Resources.class);
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled))
.thenReturn(true);
mController = new PreventRingingGesturePreferenceController(mContext, null);
+ mController.mPreferenceCategory = new PreferenceCategory(mContext);
mController.mVibratePref = new RadioButtonPreference(mContext);
- mController.mNonePref = new RadioButtonPreference(mContext);
mController.mMutePref = new RadioButtonPreference(mContext);
}
@@ -79,9 +82,10 @@
public void testUpdateState_mute() {
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
Settings.Secure.VOLUME_HUSH_MUTE);
- mController.updateState(null);
+ mController.updateState(mPreference);
+ assertThat(mController.mVibratePref.isEnabled()).isTrue();
+ assertThat(mController.mMutePref.isEnabled()).isTrue();
assertThat(mController.mVibratePref.isChecked()).isFalse();
- assertThat(mController.mNonePref.isChecked()).isFalse();
assertThat(mController.mMutePref.isChecked()).isTrue();
}
@@ -89,9 +93,21 @@
public void testUpdateState_vibrate() {
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
Settings.Secure.VOLUME_HUSH_VIBRATE);
- mController.updateState(null);
+ mController.updateState(mPreference);
+ assertThat(mController.mVibratePref.isEnabled()).isTrue();
+ assertThat(mController.mMutePref.isEnabled()).isTrue();
assertThat(mController.mVibratePref.isChecked()).isTrue();
- assertThat(mController.mNonePref.isChecked()).isFalse();
+ assertThat(mController.mMutePref.isChecked()).isFalse();
+ }
+
+ @Test
+ public void testUpdateState_off() {
+ Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
+ Settings.Secure.VOLUME_HUSH_OFF);
+ mController.updateState(mPreference);
+ assertThat(mController.mVibratePref.isEnabled()).isFalse();
+ assertThat(mController.mMutePref.isEnabled()).isFalse();
+ assertThat(mController.mVibratePref.isChecked()).isFalse();
assertThat(mController.mMutePref.isChecked()).isFalse();
}
@@ -99,9 +115,8 @@
public void testUpdateState_other() {
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
7);
- mController.updateState(null);
+ mController.updateState(mPreference);
assertThat(mController.mVibratePref.isChecked()).isFalse();
- assertThat(mController.mNonePref.isChecked()).isTrue();
assertThat(mController.mMutePref.isChecked()).isFalse();
}
@@ -132,19 +147,4 @@
Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.VOLUME_HUSH_GESTURE, Settings.Secure.VOLUME_HUSH_OFF));
}
-
- @Test
- public void testRadioButtonClicked_off() {
- RadioButtonPreference rbPref = new RadioButtonPreference(mContext);
- rbPref.setKey(PreventRingingGesturePreferenceController.KEY_NONE);
-
- Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
- Settings.Secure.VOLUME_HUSH_MUTE);
-
- mController.onRadioButtonClicked(rbPref);
-
- assertThat(Settings.Secure.VOLUME_HUSH_OFF).isEqualTo(
- Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.VOLUME_HUSH_GESTURE, Settings.Secure.VOLUME_HUSH_VIBRATE));
- }
}
diff --git a/tests/robotests/src/com/android/settings/gestures/PreventRingingSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/PreventRingingSwitchPreferenceControllerTest.java
new file mode 100644
index 0000000..5f221f5
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/gestures/PreventRingingSwitchPreferenceControllerTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.gestures;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.provider.Settings;
+
+import androidx.preference.Preference;
+
+import com.android.settings.widget.SwitchBar;
+
+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 PreventRingingSwitchPreferenceControllerTest {
+ private Context mContext;
+ private Resources mResources;
+ private PreventRingingSwitchPreferenceController mController;
+ private Preference mPreference = mock(Preference.class);
+
+ @Before
+ public void setUp() {
+ mContext = spy(RuntimeEnvironment.application);
+ mResources = mock(Resources.class);
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled))
+ .thenReturn(true);
+ mController = new PreventRingingSwitchPreferenceController(mContext);
+ mController.mSwitch = mock(SwitchBar.class);
+ }
+
+ @Test
+ public void testIsAvailable_configIsTrue_shouldReturnTrue() {
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_volumeHushGestureEnabled)).thenReturn(true);
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void testIsAvailable_configIsFalse_shouldReturnFalse() {
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_volumeHushGestureEnabled)).thenReturn(false);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void testOn_updateState_hushOff() {
+ Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
+ Settings.Secure.VOLUME_HUSH_OFF);
+ mController.updateState(mPreference);
+ verify(mController.mSwitch, times(1)).setChecked(false);
+ }
+
+ @Test
+ public void testOn_updateState_hushVibrate() {
+ Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
+ Settings.Secure.VOLUME_HUSH_VIBRATE);
+ mController.updateState(mPreference);
+ verify(mController.mSwitch, times(1)).setChecked(true);
+ }
+
+ @Test
+ public void testOn_updateState_hushMute() {
+ Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
+ Settings.Secure.VOLUME_HUSH_MUTE);
+ mController.updateState(mPreference);
+ verify(mController.mSwitch, times(1)).setChecked(true);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
index c62a6bb..c47fa38 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
@@ -29,16 +29,16 @@
import com.android.settings.slices.CustomSliceRegistry;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
@RunWith(RobolectricTestRunner.class)
public class ContextualCardLoaderTest {
@@ -82,29 +82,29 @@
}
@Test
- public void getFinalDisplayableCards_twoEligibleCards_shouldShowAll() {
+ public void getDisplayableCards_twoEligibleCards_shouldShowAll() {
final List<ContextualCard> cards = getContextualCardList().stream().limit(2)
.collect(Collectors.toList());
doReturn(cards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
- final List<ContextualCard> result = mContextualCardLoader.getFinalDisplayableCards(cards);
+ final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
assertThat(result).hasSize(cards.size());
}
@Test
- public void getFinalDisplayableCards_fiveEligibleCardsNoLarge_shouldShowDefaultCardCount() {
+ public void getDisplayableCards_fiveEligibleCardsNoLarge_shouldShowDefaultCardCount() {
final List<ContextualCard> fiveCards = getContextualCardListWithNoLargeCard();
doReturn(fiveCards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
- final List<ContextualCard> result = mContextualCardLoader.getFinalDisplayableCards(
+ final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(
fiveCards);
assertThat(result).hasSize(DEFAULT_CARD_COUNT);
}
@Test
- public void getFinalDisplayableCards_threeEligibleCardsOneLarge_shouldShowThreeCards() {
+ public void getDisplayableCards_threeEligibleCardsOneLarge_shouldShowThreeCards() {
final List<ContextualCard> cards = getContextualCardList().stream().limit(2)
.collect(Collectors.toList());
cards.add(new ContextualCard.Builder()
@@ -115,18 +115,18 @@
.build());
doReturn(cards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
- final List<ContextualCard> result = mContextualCardLoader.getFinalDisplayableCards(cards);
+ final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(cards);
assertThat(result).hasSize(3);
}
@Test
- public void getFinalDisplayableCards_threeEligibleCardsTwoLarge_shouldShowTwoCards() {
+ public void getDisplayableCards_threeEligibleCardsTwoLarge_shouldShowTwoCards() {
final List<ContextualCard> threeCards = getContextualCardList().stream().limit(3)
.collect(Collectors.toList());
doReturn(threeCards).when(mContextualCardLoader).filterEligibleCards(any(List.class));
- final List<ContextualCard> result = mContextualCardLoader.getFinalDisplayableCards(
+ final List<ContextualCard> result = mContextualCardLoader.getDisplayableCards(
threeCards);
assertThat(result).hasSize(2);
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
index c405ffc..3fc8e06 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
@@ -32,6 +32,8 @@
import com.android.settings.homepage.contextualcards.conditional.ConditionFooterContextualCard;
import com.android.settings.homepage.contextualcards.conditional.ConditionHeaderContextualCard;
import com.android.settings.homepage.contextualcards.conditional.ConditionalContextualCard;
+import com.android.settings.intelligence.ContextualCardProto;
+import com.android.settings.slices.CustomSliceRegistry;
import org.junit.Before;
import org.junit.Test;
@@ -203,6 +205,134 @@
assertThat(actualCards).containsExactlyElementsIn(expectedCards);
}
+
+ @Test
+ public void assignCardWidth_noSuggestionCards_shouldNotHaveHalfCards() {
+ final List<Integer> categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE
+ );
+ final List<ContextualCard> noSuggestionCards = buildCategoriedCards(getContextualCardList(),
+ categories);
+
+ final List<ContextualCard> result = mManager.assignCardWidth(noSuggestionCards);
+
+ assertThat(result).hasSize(5);
+ for (ContextualCard card : result) {
+ assertThat(card.isHalfWidth()).isFalse();
+ }
+ }
+
+ @Test
+ public void assignCardWidth_oneSuggestionCards_shouldNotHaveHalfCards() {
+ final List<Integer> categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
+ );
+ final List<ContextualCard> oneSuggestionCards = buildCategoriedCards(
+ getContextualCardList(), categories);
+
+ final List<ContextualCard> result = mManager.assignCardWidth(oneSuggestionCards);
+
+ assertThat(result).hasSize(5);
+ for (ContextualCard card : result) {
+ assertThat(card.isHalfWidth()).isFalse();
+ }
+ }
+
+ @Test
+ public void assignCardWidth_twoConsecutiveSuggestionCards_shouldHaveTwoHalfCards() {
+ final List<Integer> categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE
+ );
+ final List<ContextualCard> twoConsecutiveSuggestionCards = buildCategoriedCards(
+ getContextualCardList(), categories);
+ final List<Boolean> expectedValues = Arrays.asList(false, false, true, true, false);
+
+ final List<ContextualCard> result = mManager.assignCardWidth(
+ twoConsecutiveSuggestionCards);
+
+ assertThat(result).hasSize(5);
+ for (int i = 0; i < result.size(); i++) {
+ assertThat(result.get(i).isHalfWidth()).isEqualTo(expectedValues.get(i));
+ }
+ }
+
+ @Test
+ public void assignCardWidth_twoNonConsecutiveSuggestionCards_shouldNotHaveHalfCards() {
+ final List<Integer> categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
+ );
+ final List<ContextualCard> twoNonConsecutiveSuggestionCards = buildCategoriedCards(
+ getContextualCardList(), categories);
+
+ final List<ContextualCard> result = mManager.assignCardWidth(
+ twoNonConsecutiveSuggestionCards);
+
+ assertThat(result).hasSize(5);
+ for (ContextualCard card : result) {
+ assertThat(card.isHalfWidth()).isFalse();
+ }
+ }
+
+ @Test
+ public void assignCardWidth_threeConsecutiveSuggestionCards_shouldHaveTwoHalfCards() {
+ final List<Integer> categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE
+ );
+ final List<ContextualCard> threeConsecutiveSuggestionCards = buildCategoriedCards(
+ getContextualCardList(), categories);
+ final List<Boolean> expectedValues = Arrays.asList(false, true, true, false, false);
+
+ final List<ContextualCard> result = mManager.assignCardWidth(
+ threeConsecutiveSuggestionCards);
+
+ assertThat(result).hasSize(5);
+ for (int i = 0; i < result.size(); i++) {
+ assertThat(result.get(i).isHalfWidth()).isEqualTo(expectedValues.get(i));
+ }
+ }
+
+ @Test
+ public void assignCardWidth_fourConsecutiveSuggestionCards_shouldHaveFourHalfCards() {
+ final List<Integer> categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
+ );
+ final List<ContextualCard> fourConsecutiveSuggestionCards = buildCategoriedCards(
+ getContextualCardList(), categories);
+ final List<Boolean> expectedValues = Arrays.asList(false, true, true, true, true);
+
+ final List<ContextualCard> result = mManager.assignCardWidth(
+ fourConsecutiveSuggestionCards);
+
+ assertThat(result).hasSize(5);
+ for (int i = 0; i < result.size(); i++) {
+ assertThat(result.get(i).isHalfWidth()).isEqualTo(expectedValues.get(i));
+ }
+ }
+
private ContextualCard buildContextualCard(String sliceUri) {
return new ContextualCard.Builder()
.setName(TEST_SLICE_NAME)
@@ -210,4 +340,45 @@
.setSliceUri(Uri.parse(sliceUri))
.build();
}
+
+ private List<ContextualCard> buildCategoriedCards(List<ContextualCard> cards,
+ List<Integer> categories) {
+ final List<ContextualCard> result = new ArrayList<>();
+ for (int i = 0; i < cards.size(); i++) {
+ result.add(cards.get(i).mutate().setCategory(categories.get(i)).build());
+ }
+ return result;
+ }
+
+ private List<ContextualCard> getContextualCardList() {
+ final List<ContextualCard> cards = new ArrayList<>();
+ cards.add(new ContextualCard.Builder()
+ .setName("test_wifi")
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI)
+ .build());
+ cards.add(new ContextualCard.Builder()
+ .setName("test_flashlight")
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(
+ Uri.parse("content://com.android.settings.test.slices/action/flashlight"))
+ .build());
+ cards.add(new ContextualCard.Builder()
+ .setName("test_connected")
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI)
+ .build());
+ cards.add(new ContextualCard.Builder()
+ .setName("test_gesture")
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(Uri.parse(
+ "content://com.android.settings.test.slices/action/gesture_pick_up"))
+ .build());
+ cards.add(new ContextualCard.Builder()
+ .setName("test_battery")
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(CustomSliceRegistry.BATTERY_INFO_SLICE_URI)
+ .build());
+ return cards;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardControllerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardControllerTest.java
index 566ca07..4553f7c 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardControllerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardControllerTest.java
@@ -112,7 +112,8 @@
}
@Test
- public void getConditionalCards_hasOneConditionCard_shouldGetOneFullWidthCard() {
+ public void getConditionalCards_hasOneConditionCardAndExpanded_shouldGetOneFullWidthCard() {
+ mController.setIsExpanded(true);
final Map<Integer, List<ContextualCard>> conditionalCards =
mController.buildConditionalCardsWithFooterOrHeader(generateConditionCards(1));
@@ -120,11 +121,24 @@
assertThat(conditionalCards.get(CardType.CONDITIONAL)).hasSize(1);
assertThat(conditionalCards.get(CardType.CONDITIONAL).get(0).isHalfWidth()).isFalse();
assertThat(conditionalCards.get(CardType.CONDITIONAL_HEADER)).isEmpty();
+ assertThat(conditionalCards.get(CardType.CONDITIONAL_FOOTER)).isNotEmpty();
+ }
+
+ @Test
+ public void getConditionalCards_hasOneConditionCardAndCollapsed_shouldGetConditionalHeader() {
+ mController.setIsExpanded(false);
+ final Map<Integer, List<ContextualCard>> conditionalCards =
+ mController.buildConditionalCardsWithFooterOrHeader(generateConditionCards(1));
+
+ assertThat(conditionalCards).hasSize(3);
+ assertThat(conditionalCards.get(CardType.CONDITIONAL)).isEmpty();
+ assertThat(conditionalCards.get(CardType.CONDITIONAL_HEADER)).isNotEmpty();
assertThat(conditionalCards.get(CardType.CONDITIONAL_FOOTER)).isEmpty();
}
@Test
- public void getConditionalCards_hasTwoConditionCards_shouldGetTwoHalfWidthCards() {
+ public void getConditionalCards_hasTwoConditionCardsAndExpanded_shouldGetTwoHalfWidthCards() {
+ mController.setIsExpanded(true);
final Map<Integer, List<ContextualCard>> conditionalCards =
mController.buildConditionalCardsWithFooterOrHeader(generateConditionCards(2));
@@ -134,6 +148,18 @@
assertThat(card.isHalfWidth()).isTrue();
}
assertThat(conditionalCards.get(CardType.CONDITIONAL_HEADER)).isEmpty();
+ assertThat(conditionalCards.get(CardType.CONDITIONAL_FOOTER)).isNotEmpty();
+ }
+
+ @Test
+ public void getConditionalCards_hasTwoConditionCardsAndCollapsed_shouldGetConditionalHeader() {
+ mController.setIsExpanded(false);
+ final Map<Integer, List<ContextualCard>> conditionalCards =
+ mController.buildConditionalCardsWithFooterOrHeader(generateConditionCards(2));
+
+ assertThat(conditionalCards).hasSize(3);
+ assertThat(conditionalCards.get(CardType.CONDITIONAL)).isEmpty();
+ assertThat(conditionalCards.get(CardType.CONDITIONAL_HEADER)).isNotEmpty();
assertThat(conditionalCards.get(CardType.CONDITIONAL_FOOTER)).isEmpty();
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
index 0b87525..4d9a21d 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
@@ -79,17 +79,6 @@
}
@Test
- public void bindView_shouldSetScrollableToFalse() {
- RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
-
- mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
-
- assertThat(
- ((SliceContextualCardRenderer.SliceViewHolder) viewHolder).sliceView.isScrollable
- ()).isFalse();
- }
-
- @Test
public void bindView_invalidScheme_sliceShouldBeNull() {
final Uri sliceUri = Uri.parse("contet://com.android.settings.slices/action/flashlight");
RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
@@ -97,7 +86,7 @@
mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
assertThat(
- ((SliceContextualCardRenderer.SliceViewHolder) viewHolder).sliceView.getSlice())
+ ((SliceFullCardRendererHelper.SliceViewHolder) viewHolder).sliceView.getSlice())
.isNull();
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceFullCardRendererHelperTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceFullCardRendererHelperTest.java
new file mode 100644
index 0000000..9172300d
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceFullCardRendererHelperTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.homepage.contextualcards.slices;
+
+import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.net.Uri;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.slice.Slice;
+import androidx.slice.SliceProvider;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.SliceAction;
+import androidx.slice.widget.SliceLiveData;
+import androidx.slice.widget.SliceView;
+
+import com.android.settings.R;
+import com.android.settings.homepage.contextualcards.ContextualCard;
+import com.android.settings.homepage.contextualcards.slices.SliceFullCardRendererHelper.SliceViewHolder;
+import com.android.settings.intelligence.ContextualCardProto;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.Collections;
+
+@RunWith(RobolectricTestRunner.class)
+public class SliceFullCardRendererHelperTest {
+
+ private static final Uri TEST_SLICE_URI = Uri.parse("content://test/test");
+
+ private Activity mActivity;
+ private SliceFullCardRendererHelper mHelper;
+
+ @Before
+ public void setUp() {
+ // Set-up specs for SliceMetadata.
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+ mActivity = Robolectric.buildActivity(Activity.class).create().get();
+ mActivity.setTheme(R.style.Theme_Settings_Home);
+ mHelper = new SliceFullCardRendererHelper(mActivity);
+ }
+
+ @Test
+ public void createViewHolder_shouldAlwaysReturnSliceViewHolder() {
+ final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+
+ assertThat(viewHolder).isInstanceOf(SliceViewHolder.class);
+ }
+
+ @Test
+ public void bindView_shouldSetScrollableToFalse() {
+ final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+
+ mHelper.bindView(viewHolder, buildContextualCard(), buildSlice(), Collections.emptySet());
+
+ assertThat(((SliceViewHolder) viewHolder).sliceView.isScrollable()).isFalse();
+ }
+
+ @Test
+ public void bindView_shouldSetTagToSliceUri() {
+ final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+ final ContextualCard card = buildContextualCard();
+
+ mHelper.bindView(viewHolder, card, buildSlice(), Collections.emptySet());
+
+ assertThat(((SliceViewHolder) viewHolder).sliceView.getTag()).isEqualTo(card.getSliceUri());
+ }
+
+ @Test
+ public void bindView_shouldSetModeToLarge() {
+ final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+
+ mHelper.bindView(viewHolder, buildContextualCard(), buildSlice(), Collections.emptySet());
+
+ assertThat(((SliceViewHolder) viewHolder).sliceView.getMode()).isEqualTo(
+ SliceView.MODE_LARGE);
+ }
+
+ @Test
+ public void bindView_shouldSetSlice() {
+ final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+
+ mHelper.bindView(viewHolder, buildContextualCard(), buildSlice(), Collections.emptySet());
+
+ assertThat(((SliceViewHolder) viewHolder).sliceView.getSlice().getUri()).isEqualTo(
+ TEST_SLICE_URI);
+ }
+
+ private RecyclerView.ViewHolder getSliceViewHolder() {
+ final RecyclerView recyclerView = new RecyclerView(mActivity);
+ recyclerView.setLayoutManager(new LinearLayoutManager(mActivity));
+ final View view = LayoutInflater.from(mActivity).inflate(VIEW_TYPE_FULL_WIDTH, recyclerView,
+ false);
+ return mHelper.createViewHolder(view);
+ }
+
+ private ContextualCard buildContextualCard() {
+ return new ContextualCard.Builder()
+ .setName("test_name")
+ .setCategory(ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE)
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(TEST_SLICE_URI)
+ .setIsHalfWidth(false /* isHalfWidth */)
+ .build();
+ }
+
+ private Slice buildSlice() {
+ final String title = "test_title";
+ final IconCompat icon = IconCompat.createWithResource(mActivity, R.drawable.empty_icon);
+ final PendingIntent pendingIntent = PendingIntent.getActivity(
+ mActivity,
+ title.hashCode() /* requestCode */,
+ new Intent("test action"),
+ 0 /* flags */);
+ final SliceAction action
+ = SliceAction.createDeeplink(pendingIntent, icon, ListBuilder.SMALL_IMAGE, title);
+ return new ListBuilder(mActivity, TEST_SLICE_URI, ListBuilder.INFINITY)
+ .addRow(new ListBuilder.RowBuilder()
+ .addEndItem(icon, ListBuilder.ICON_IMAGE)
+ .setTitle(title)
+ .setPrimaryAction(action))
+ .build();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceHalfCardRendererHelperTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceHalfCardRendererHelperTest.java
new file mode 100644
index 0000000..c38697e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceHalfCardRendererHelperTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.homepage.contextualcards.slices;
+
+import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.net.Uri;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.slice.Slice;
+import androidx.slice.SliceProvider;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.SliceAction;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.settings.R;
+import com.android.settings.homepage.contextualcards.ContextualCard;
+import com.android.settings.homepage.contextualcards.slices.SliceHalfCardRendererHelper.HalfCardViewHolder;
+import com.android.settings.intelligence.ContextualCardProto;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class SliceHalfCardRendererHelperTest {
+
+ private static final Uri TEST_SLICE_URI = Uri.parse("content://test/test");
+
+ private Activity mActivity;
+ private SliceHalfCardRendererHelper mHelper;
+
+ @Before
+ public void setUp() {
+ // Set-up specs for SliceMetadata.
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+ mActivity = Robolectric.buildActivity(Activity.class).create().get();
+ mActivity.setTheme(R.style.Theme_Settings_Home);
+ mHelper = new SliceHalfCardRendererHelper(mActivity);
+ }
+
+ @Test
+ public void createViewHolder_shouldAlwaysReturnCustomViewHolder() {
+ final RecyclerView.ViewHolder viewHolder = getHalfCardViewHolder();
+
+ assertThat(viewHolder).isInstanceOf(HalfCardViewHolder.class);
+ }
+
+ @Test
+ public void bindView_shouldSetTitle() {
+ final RecyclerView.ViewHolder viewHolder = getHalfCardViewHolder();
+
+ mHelper.bindView(viewHolder, buildContextualCard(), buildSlice());
+
+ assertThat(((HalfCardViewHolder) viewHolder).title.getText()).isEqualTo("test_title");
+ }
+
+ private RecyclerView.ViewHolder getHalfCardViewHolder() {
+ final RecyclerView recyclerView = new RecyclerView(mActivity);
+ recyclerView.setLayoutManager(new LinearLayoutManager(mActivity));
+ final View view = LayoutInflater.from(mActivity).inflate(VIEW_TYPE_HALF_WIDTH, recyclerView,
+ false);
+
+ return mHelper.createViewHolder(view);
+ }
+
+ private ContextualCard buildContextualCard() {
+ return new ContextualCard.Builder()
+ .setName("test_name")
+ .setCategory(ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE)
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(TEST_SLICE_URI)
+ .setIsHalfWidth(false /* isHalfWidth */)
+ .build();
+ }
+
+ private Slice buildSlice() {
+ final String title = "test_title";
+ final IconCompat icon = IconCompat.createWithResource(mActivity, R.drawable.empty_icon);
+ final PendingIntent pendingIntent = PendingIntent.getActivity(
+ mActivity,
+ title.hashCode() /* requestCode */,
+ new Intent("test action"),
+ 0 /* flags */);
+ final SliceAction action
+ = SliceAction.createDeeplink(pendingIntent, icon, ListBuilder.SMALL_IMAGE, title);
+ return new ListBuilder(mActivity, TEST_SLICE_URI, ListBuilder.INFINITY)
+ .addRow(new ListBuilder.RowBuilder()
+ .addEndItem(icon, ListBuilder.ICON_IMAGE)
+ .setTitle(title)
+ .setPrimaryAction(action))
+ .build();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/location/AppLocationPermissionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/AppLocationPermissionPreferenceControllerTest.java
index 6379e44..bddd5fe 100644
--- a/tests/robotests/src/com/android/settings/location/AppLocationPermissionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/location/AppLocationPermissionPreferenceControllerTest.java
@@ -3,10 +3,12 @@
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
+import android.location.LocationManager;
import android.provider.Settings;
import androidx.lifecycle.LifecycleOwner;
+import com.android.settings.R;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
@@ -27,6 +29,7 @@
private LifecycleOwner mLifecycleOwner;
private Lifecycle mLifecycle;
+ private LocationManager mLocationManager;
@Before
public void setUp() {
@@ -35,6 +38,7 @@
mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner);
mController = new AppLocationPermissionPreferenceController(mContext, mLifecycle);
+ mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
}
@Test
@@ -52,4 +56,40 @@
assertThat(mController.isAvailable()).isTrue();
}
+
+ @Test
+ public void getSummary_whenLocationIsOff_shouldReturnStringForOff() {
+ mLocationManager.setLocationEnabledForUser(false, android.os.Process.myUserHandle());
+
+ assertThat(mController.getSummary()).isEqualTo(
+ mContext.getString(R.string.location_app_permission_summary_location_off));
+ }
+
+ @Test
+ public void getSummary_whenLocationIsOn_shouldReturnLoadingString() {
+ mLocationManager.setLocationEnabledForUser(true, android.os.Process.myUserHandle());
+
+ assertThat(mController.getSummary()).isEqualTo(
+ mContext.getString(R.string.location_settings_loading_app_permission_stats));
+ }
+
+ @Test
+ public void getSummary_whenLocationAppCountIsOne_shouldShowSingularString() {
+ mLocationManager.setLocationEnabledForUser(true, android.os.Process.myUserHandle());
+ mController.mNumBackground = 1;
+ mController.mNumTotal = 1;
+
+ assertThat(mController.getSummary()).isEqualTo(mContext.getResources().getQuantityString(
+ R.plurals.location_app_permission_summary_location_on, 1, 1, 1));
+ }
+
+ @Test
+ public void getSummary_whenLocationAppCountIsGreaterThanOne_shouldShowPluralString() {
+ mLocationManager.setLocationEnabledForUser(true, android.os.Process.myUserHandle());
+ mController.mNumBackground = 5;
+ mController.mNumTotal = 10;
+
+ assertThat(mController.getSummary()).isEqualTo(mContext.getResources().getQuantityString(
+ R.plurals.location_app_permission_summary_location_on, 5, 5, 10));
+ }
}
diff --git a/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java
new file mode 100644
index 0000000..3b33558
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.location;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settingslib.location.RecentLocationAccesses;
+import com.android.settingslib.widget.LayoutPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+public class RecentLocationAccessPreferenceControllerTest {
+ @Mock
+ private LayoutPreference mLayoutPreference;
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private RecentLocationAccesses mRecentLocationApps;
+
+ private Context mContext;
+ private RecentLocationAccessPreferenceController mController;
+ private View mAppEntitiesHeaderView;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ mController = spy(
+ new RecentLocationAccessPreferenceController(mContext, mRecentLocationApps));
+ final String key = mController.getPreferenceKey();
+ mAppEntitiesHeaderView = LayoutInflater.from(mContext).inflate(
+ R.layout.app_entities_header, null /* root */);
+ when(mScreen.findPreference(key)).thenReturn(mLayoutPreference);
+ when(mLayoutPreference.getKey()).thenReturn(key);
+ when(mLayoutPreference.getContext()).thenReturn(mContext);
+ when(mLayoutPreference.findViewById(R.id.app_entities_header)).thenReturn(
+ mAppEntitiesHeaderView);
+ }
+
+ /** Verifies the title text, details text are correct, and the click listener is set. */
+ @Test
+ public void updateState_whenAppListIsEmpty_shouldDisplayTitleTextAndDetailsText() {
+ doReturn(new ArrayList<>()).when(mRecentLocationApps).getAppListSorted();
+ mController.displayPreference(mScreen);
+ mController.updateState(mLayoutPreference);
+
+ final TextView title = mAppEntitiesHeaderView.findViewById(R.id.header_title);
+ assertThat(title.getText()).isEqualTo(
+ mContext.getText(R.string.location_category_recent_location_access));
+ final TextView details = mAppEntitiesHeaderView.findViewById(R.id.header_details);
+ assertThat(details.getText()).isEqualTo(
+ mContext.getText(R.string.location_recent_location_access_view_details));
+ assertThat(details.hasOnClickListeners()).isTrue();
+ }
+
+ @Test
+ public void updateState_whenAppListMoreThanThree_shouldDisplayTopThreeApps() {
+ final List<RecentLocationAccesses.Access> accesses = createMockAccesses(6);
+ doReturn(accesses).when(mRecentLocationApps).getAppListSorted();
+ mController.displayPreference(mScreen);
+ mController.updateState(mLayoutPreference);
+
+ // The widget can display the top 3 apps from the list when there're more than 3.
+ final View app1View = mAppEntitiesHeaderView.findViewById(R.id.app1_view);
+ final ImageView appIconView1 = app1View.findViewById(R.id.app_icon);
+ final TextView appTitle1 = app1View.findViewById(R.id.app_title);
+ final TextView appSummary1 = app1View.findViewById(R.id.app_summary);
+
+ assertThat(app1View.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(appIconView1.getDrawable()).isNotNull();
+ assertThat(appTitle1.getText()).isEqualTo("appTitle0");
+ assertThat(appSummary1.getText()).isEqualTo("appSummary0");
+
+ final View app2View = mAppEntitiesHeaderView.findViewById(R.id.app2_view);
+ final ImageView appIconView2 = app2View.findViewById(R.id.app_icon);
+ final TextView appTitle2 = app2View.findViewById(R.id.app_title);
+ final TextView appSummary2 = app2View.findViewById(R.id.app_summary);
+
+ assertThat(app2View.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(appIconView2.getDrawable()).isNotNull();
+ assertThat(appTitle2.getText()).isEqualTo("appTitle1");
+ assertThat(appSummary2.getText()).isEqualTo("appSummary1");
+
+ final View app3View = mAppEntitiesHeaderView.findViewById(R.id.app3_view);
+ final ImageView appIconView3 = app3View.findViewById(R.id.app_icon);
+ final TextView appTitle3 = app3View.findViewById(R.id.app_title);
+ final TextView appSummary3 = app3View.findViewById(R.id.app_summary);
+
+ assertThat(app3View.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(appIconView3.getDrawable()).isNotNull();
+ assertThat(appTitle3.getText()).isEqualTo("appTitle2");
+ assertThat(appSummary3.getText()).isEqualTo("appSummary2");
+ }
+
+ private List<RecentLocationAccesses.Access> createMockAccesses(int count) {
+ final List<RecentLocationAccesses.Access> accesses = new ArrayList<>();
+ for (int i = 0; i < count; i++) {
+ final Drawable icon = mock(Drawable.class);
+ // Add mock accesses
+ final RecentLocationAccesses.Access access = new RecentLocationAccesses.Access(
+ "packageName", android.os.Process.myUserHandle(), icon,
+ "appTitle" + i, "appSummary" + i, 1000 - i);
+ accesses.add(access);
+ }
+ return accesses;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java
index 8ed9dcc..cd70d66 100644
--- a/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.nfc.NfcAdapter;
import android.nfc.NfcManager;
import android.os.UserHandle;
@@ -57,6 +58,8 @@
private UserManager mUserManager;
@Mock
private PreferenceScreen mScreen;
+ @Mock
+ private PackageManager mPackageManager;
private RestrictedPreference mAndroidBeamPreference;
private AndroidBeamPreferenceController mAndroidBeamController;
@@ -78,6 +81,8 @@
mAndroidBeamPreference = new RestrictedPreference(RuntimeEnvironment.application);
when(mScreen.findPreference(mAndroidBeamController.getPreferenceKey())).thenReturn(
mAndroidBeamPreference);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC_BEAM)).thenReturn(true);
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
@@ -95,6 +100,13 @@
}
@Test
+ public void isAvailable_noNfcFeature_shouldReturnFalse() {
+ when(mNfcAdapter.isEnabled()).thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC_BEAM)).thenReturn(false);
+ assertThat(mAndroidBeamController.isAvailable()).isFalse();
+ }
+
+ @Test
public void isAvailable_noNfcAdapter_shouldReturnFalse() {
ReflectionHelpers.setField(mAndroidBeamController, "mNfcAdapter", null);
assertThat(mAndroidBeamController.isAvailable()).isFalse();
diff --git a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
index e64fae7..17516e9 100644
--- a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
@@ -111,14 +111,17 @@
ShadowLooper.getShadowMainLooper().runToEndOfTasks();
assertThat(fakeFragment.bCalledStopAndPop).isTrue();
+ assertThat(fakeFragment.errorType).isEqualTo(ERROR_DIALOG_TYPE.TIME_OUT);
}
class FakeNetworkRequestDialogFragment extends NetworkRequestDialogFragment {
boolean bCalledStopAndPop = false;
+ ERROR_DIALOG_TYPE errorType = null;
@Override
- public void stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE type) {
+ public void stopScanningAndMaybePopErrorDialog(ERROR_DIALOG_TYPE type) {
bCalledStopAndPop = true;
+ errorType = type;
}
}
@@ -150,22 +153,28 @@
@Test
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();
+ // Assert
+ FakeNetworkRequestDialogFragment fakeFragment = new FakeNetworkRequestDialogFragment();
+ FakeNetworkRequestDialogFragment spyFakeFragment = spy(fakeFragment);
- // Test if config would update list.
+ List<AccessPoint> accessPointList = createAccessPointList();
+ when(spyFakeFragment.getAccessPointList()).thenReturn(accessPointList);
+
+ spyFakeFragment.show(mActivity.getSupportFragmentManager(), null);
+
+ // Action
WifiConfiguration config = new WifiConfiguration();
config.SSID = "Test AP 3";
- networkRequestDialogFragment.onUserSelectionConnectSuccess(config);
+ spyFakeFragment.onUserSelectionConnectSuccess(config);
- assertThat(alertDialog.isShowing()).isFalse();
+ // Check
+ ShadowLooper.getShadowMainLooper().runToEndOfTasks();
+ assertThat(fakeFragment.bCalledStopAndPop).isTrue();
+ assertThat(fakeFragment.errorType).isNull();
}
@Test
- public void updateAccessPointList_onUserSelectionConnectFailure_shouldCallTimeoutDialog() {
+ public void updateAccessPointList_onUserSelectionConnectFailure_shouldCallAbortDialog() {
FakeNetworkRequestDialogFragment fakeFragment = new FakeNetworkRequestDialogFragment();
FakeNetworkRequestDialogFragment spyFakeFragment = spy(fakeFragment);
List<AccessPoint> accessPointList = createAccessPointList();
@@ -181,6 +190,7 @@
fakeFragment.onUserSelectionConnectFailure(config);
assertThat(fakeFragment.bCalledStopAndPop).isTrue();
+ assertThat(fakeFragment.errorType).isEqualTo(ERROR_DIALOG_TYPE.ABORT);
}
@Test
diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
index 61033e9..8e64f5f 100644
--- a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
+++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
@@ -38,6 +38,7 @@
Intent intent = new Intent(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_SCANNER);
intent.putExtra(WifiDppUtils.EXTRA_WIFI_SECURITY, "WEP");
intent.putExtra(WifiDppUtils.EXTRA_WIFI_SSID, "GoogleGuest");
+ intent.putExtra(WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY, "password");
mActivityRule.launchActivity(intent);
@@ -50,6 +51,7 @@
WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
intent.putExtra(WifiDppUtils.EXTRA_WIFI_SECURITY, "WEP");
intent.putExtra(WifiDppUtils.EXTRA_WIFI_SSID, "GoogleGuest");
+ intent.putExtra(WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY, "password");
mActivityRule.launchActivity(intent);
@@ -59,7 +61,10 @@
@Test
public void launchActivity_chooseSavedWifiNetwork_shouldNotAutoFinish() {
Intent intent = new Intent(
- WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_CHOOSE_SAVED_WIFI_NETWORK);
+ WifiDppConfiguratorActivity.ACTION_PROCESS_WIFI_DPP_QR_CODE);
+ String qrCode = "DPP:I:SN=4774LH2b4044;M:010203040506;K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD"
+ + "IgADURzxmttZoIRIPWGoQMV00XHWCAQIhXruVWOz0NjlkIA=;;";
+ intent.putExtra(WifiDppUtils.EXTRA_QR_CODE, qrCode);
mActivityRule.launchActivity(intent);